พังพอนดัชนีเฉพาะไม่ทำงาน!


95

ฉันกำลังพยายามให้ MongoDB ตรวจพบค่าที่ซ้ำกันตามดัชนี ฉันคิดว่าสิ่งนี้เป็นไปได้ใน MongoDB แต่ดูเหมือนว่าสิ่งที่ห่อหุ้มพังพอนจะแตก ดังนั้นสำหรับสิ่งนี้:

User = new Schema ({
  email: {type: String, index: {unique: true, dropDups: true}}
})

ฉันสามารถบันทึกผู้ใช้ 2 คนด้วยอีเมลเดียวกัน ยี้.

มีการแสดงปัญหาเดียวกันที่นี่: https://github.com/LearnBoost/mongoose/issues/56แต่เธรดนั้นเก่าและไม่มีที่ไหนเลย

ตอนนี้ฉันโทรไปที่ฐานข้อมูลด้วยตนเองเพื่อค้นหาผู้ใช้ การโทรนั้นไม่แพงเนื่องจากมีการจัดทำดัชนี "อีเมล" แต่ก็ยังเป็นการดีที่จะปล่อยให้มันถูกจัดการโดยกำเนิด

ใครมีวิธีแก้ปัญหานี้หรือไม่?


1
ข่าวร้ายมันยังคงเป็นปัญหากับ mongod v2.4.3 พังพอน v3.6.20
ชื้นที่

ไม่ซ้ำกันดูเหมือนจะทำงานบนโฮสต์ของฉัน แต่ล้มเหลวในการบังคับใช้สิ่งที่ไม่ซ้ำกันโดยใช้โหนด / รหัสพังพอนเดียวกันกับโฮสต์อื่น โฮสต์ที่ทำงานได้อย่างถูกต้องทำงานอย่างถูกต้อง mongod 3.4.10 เดียวซึ่งไม่ได้ - รันการจำลองที่ตั้งค่าด้วย mongod 3.2.17 บนโฮสต์ทั้งสองฉันกำลังสร้างคอลเลกชันตั้งแต่เริ่มต้นดังนั้นการ dups ที่มีอยู่จึงไม่ใช่ปัญหา ฉันได้ลองใช้วิธีแก้ปัญหาส่วนใหญ่ในหน้านี้แล้วและวิธีที่ได้ผลคือพังพอน-unique-validator จาก @Isaac Pak
Maksym

คำตอบ:


95

อ๊ะ! คุณต้องรีสตาร์ท mongo


4
ฉันมีปัญหาเดียวกัน แต่ไม่พบวิธีรีสตาร์ท mongo บน OSX เมื่อฉันฆ่ากระบวนการมันก็จะเกิดอีกครั้งโดยอัตโนมัติและดัชนีเฉพาะยังไม่ทำงาน ... มีความคิดใดบ้าง?
ragulka

7
คุณหมายถึงอะไร "อ๊ะคุณเพิ่งเริ่ม mongo ใหม่"! คุณกำลังบอกว่าเป็นไปไม่ได้ที่จะเพิ่มดัชนีโดยไม่นำฐานข้อมูลลง?
andrewrk

7
นี่ไม่เป็นความจริง คุณไม่จำเป็นต้องรีสตาร์ท mongo เพื่อเพิ่มดัชนี
JohnnyHK

1
สำหรับสิ่งที่ไม่เหมือนใคร .. ฉันต้องรีสตาร์ท mongo .. และมันได้ผล .. ขอบคุณ!
Muhammad Ahsan Ayaz

2
ฉันลองรีสตาร์ท ยังทำดัชนีอีกครั้ง ต้องวางฐานข้อมูลเพื่อแก้ไขปัญหานี้ การคาดเดาปัญหาคือมีรายการที่ซ้ำกันอยู่แล้วก่อนที่จะเพิ่มดัชนีดังนั้นในฐานข้อมูลการผลิตฉันจะต้องลบรายการที่ซ้ำกันแล้วรีสตาร์ท?
isimmons

40

อ๊ะ! คุณต้องรีสตาร์ท mongo

และจัดทำดัชนีใหม่ด้วย:

mongo <db-name>
> db.<collection-name>.reIndex()

ในการทดสอบเนื่องจากฉันไม่มีข้อมูลสำคัญคุณสามารถทำสิ่งต่อไปนี้ได้

mongo <db-name>
> db.dropDatabase()

16
db.dropDatabase () เช็ดฐานข้อมูลของคุณ!
Isaac Pak

28

ฉันพบปัญหาเดียวกัน: ฉันได้เพิ่มข้อ จำกัด เฉพาะสำหรับemailฟิลด์ไปยังของเราUserSchemaหลังจากที่ได้เพิ่มผู้ใช้ไปยังฐานข้อมูลแล้วและยังสามารถบันทึกผู้ใช้ด้วยอีเมลหลอกลวงได้ ฉันแก้ไขปัญหานี้โดยทำสิ่งต่อไปนี้:

1) ลบเอกสารทั้งหมดออกจากคอลเลกชันผู้ใช้

2) จาก mongo shell ให้รันคำสั่ง: db.users.createIndex({email: 1}, {unique: true})

เกี่ยวกับขั้นตอนที่ 1 โปรดทราบว่าจากเอกสารของ Mongo:

MongoDB ไม่สามารถสร้างดัชนีเฉพาะบนฟิลด์ดัชนีที่ระบุได้หากคอลเล็กชันมีข้อมูลที่ละเมิดข้อ จำกัด เฉพาะสำหรับดัชนีอยู่แล้ว

https://docs.mongodb.com/manual/core/index-unique/


11

พฤติกรรมนี้จะเกิดขึ้นเช่นกันหากคุณทิ้งรายการที่ซ้ำกันไว้ใน Mongo พังพอนจะพยายามสร้างมันใน Mongo เมื่อแอปพลิเคชันของคุณเริ่มต้นขึ้น

เพื่อป้องกันปัญหานี้คุณสามารถจัดการกับข้อผิดพลาดนี้ได้ด้วยวิธีนี้:

yourModel.on('index', function(err) {
  if (err?) {
    console.error err
  }
);

10

โอเคฉันสามารถแก้ไขปัญหานี้ได้จาก mongoshell โดยการเพิ่มดัชนีในฟิลด์และตั้งค่าคุณสมบัติเฉพาะ:

db.<collectionName>.ensureIndex({fieldName: 1}, {unique: true});

เชลล์ควรตอบสนองในลักษณะนี้:

{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}

ตอนนี้เพื่อทดสอบอย่างรวดเร็วจาก mongoshell:

var doc = {fieldName: 'abc'};
db.<collectionName>.insert(doc)

ควรให้: WriteResult ({"nInserted": 1})

แต่เมื่อทำซ้ำอีกครั้ง:

db.<collectionName>.insert(doc)

จะให้:

WriteResult({
    "nInserted" : 0,
    "writeError" : {
        "code" : 11000,
        "errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: fuelConsumption.users.$email_1  dup key: { : \"martyna@martycud.com\" }"
    }
})

10

ฉันได้ทำสิ่งนี้แล้ว:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const FooSchema = new Schema({
   name: { type: String, required: true, index: true, unique: true }
});

const Foo = mongoose.model('Foo', FooSchema);

Foo.createIndexes();

module.exports = Foo

ฉันเพิ่มFoo.createIndexes()บรรทัด bc ฉันได้รับคำเตือนการเลิกใช้งานต่อไปนี้เมื่อโค้ดถูกรัน:

(node:21553) DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes instead.

ฉันไม่แน่ใจว่าFoo.createIndexes()เป็นแบบอะซิงโครนัสหรือเปล่าแต่ดูเหมือนว่า AFAIK จะทำงานได้ดี


คำตอบเดียวสำหรับคำถามที่ตอบปัญหาแทนที่จะวนเวียนอยู่กับมัน
Saksham Gupta

คำตอบนี้ช่วยฉัน สิ่งที่ฉันขาดหายไปคือการindex: trueสร้างดัชนีเฉพาะของฉันขึ้นมา
elcid

6

ตามเอกสาร: https://docs.mongodb.com/v2.6/tutorial/modify-an-index/

ในการแก้ไขดัชนีที่มีอยู่คุณต้องปล่อยและสร้างดัชนีใหม่

อย่ารีสตาร์ท MONGO!

1 - วางคอลเลคชัน

db.users.drop()

2 - ทำดัชนีตารางอีกครั้ง

db.users.ensureIndex({email: 1, type: 1}, {unique: true})

มันบอกว่าดัชนีหล่นไม่ใช่คอลเลกชัน
Zero0Ho

5

พังพอนหลวมเล็กน้อยเมื่อบังคับใช้ดัชนีเฉพาะจากระดับแอปพลิเคชัน ดังนั้นจึงควรบังคับใช้ดัชนีเฉพาะของคุณจากฐานข้อมูลโดยใช้ mongo cli หรือบอกพังพอนอย่างชัดเจนว่าคุณจริงจังกับuniqueดัชนีโดยการเขียนโค้ดบรรทัดต่อไปนี้หลังจาก UserSchema ของคุณ:

UserSchema.index({ username: 1, email: 1 }, { unique: true});

สิ่งนี้จะบังคับใช้ดัชนีที่ไม่ซ้ำกันทั้งในusernameและemailฟิลด์ใน UserSchema ของคุณ ไชโย


5
ไปปาร์ตี้ช้าไปหน่อย แต่สิ่งที่ดีคือ ORM ที่ "หลวมไปหน่อยเมื่อบังคับใช้ดัชนีที่ไม่ซ้ำกัน"
Imre_G

การดูหมิ่นความคิดเห็นที่ดีนั้นไม่ได้ช่วยอะไรเลย โซลูชันนี้เป็นของแข็งและพร้อมสำหรับการผลิต
Isaac Pak

4

พังพอนจะไม่สามารถเพิ่มดัชนีเฉพาะเมื่อ:

  1. คอลเล็กชันมีดัชนีชื่อเดียวกันอยู่แล้ว
  2. คอลเล็กชันมีเอกสารที่ซ้ำกับฟิลด์ที่จัดทำดัชนีไว้แล้ว

ในกรณีแรกที่รายการดัชนีที่มีและลดลงดัชนีเก่าด้วยdb.collection.getIndexes() db.collection.dropIndex("index_name")เมื่อคุณรีสตาร์ทแอปพลิเคชัน Mongoose ควรเพิ่มดัชนีใหม่อย่างถูกต้อง

ในกรณีที่สองคุณต้องลบรายการที่ซ้ำกันออกก่อนที่จะรีสตาร์ทแอปพลิเคชัน Mongoose


3

พังพอน - ตัวตรวจสอบที่ไม่ซ้ำกัน

วิธีใช้ปลั๊กอินนี้:

1) การติดตั้ง npm - บันทึก mongoose-unique-validator

2) ในสคีมาของคุณให้ทำตามคำแนะนำนี้:

// declare this at the top
var mongoose = require('mongoose');
var uniqueValidator = require('mongoose-unique-validator');

// exampleSchema = mongoose.Schema({}) etc...

exampleSchema.plugin(uniqueValidator);

// module.exports = mongoose.model(...) etc....

3) วิธีพังพอน

เมื่อใช้วิธีการเช่นfindOneAndUpdateคุณจะต้องส่งผ่านวัตถุการกำหนดค่านี้:

{ runValidators: true, context: 'query' }

ie. User.findOneAndUpdate(
      { email: 'old-email@example.com' },
      { email: 'new-email@example.com' },
      { runValidators: true, context: 'query' },
      function(err) {
        // ...
    }

4) ตัวเลือกเพิ่มเติม

  1. ไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่

    ใช้อ็อพชัน uniqueCaseInsensitive ในสคีมาของคุณ

    ie. email: { type: String, index: true, unique: true, required: true, uniqueCaseInsensitive: true }

  2. ข้อความแสดงข้อผิดพลาดที่กำหนดเอง

    ie. exampleSchema.plugin(uniqueValidator, { message: 'Error, expected {PATH} to be unique.' });

ตอนนี้คุณสามารถเพิ่ม / ลบคุณสมบัติเฉพาะในสกีมาของคุณได้โดยไม่ต้องกังวลกับการรีสตาร์ท mongo วางฐานข้อมูลหรือสร้างดัชนี

ข้อควรระวัง (จากเอกสาร):

เนื่องจากเราใช้การดำเนินการ async ในการตรวจสอบว่ามีเอกสารอยู่ในฐานข้อมูลหรือไม่จึงเป็นไปได้ที่แบบสอบถามสองรายการจะดำเนินการพร้อมกันทั้งคู่จะได้รับ 0 กลับจากนั้นทั้งคู่จึงแทรกลงใน MongoDB

นอกเหนือจากการล็อกคอลเลกชันโดยอัตโนมัติหรือบังคับให้มีการเชื่อมต่อเพียงครั้งเดียวแล้วยังไม่มีวิธีแก้ปัญหาที่แท้จริง

สำหรับผู้ใช้ส่วนใหญ่ของเราสิ่งนี้จะไม่เป็นปัญหา แต่เป็นกรณีที่ต้องระวัง


2

คำตอบใหม่ล่าสุด: ไม่จำเป็นต้องรีสตาร์ท mongodb เลยหาก Colleciton มีดัชนีชื่อเดียวกันอยู่แล้วพังพอนจะไม่สร้างดัชนีของคุณใหม่อีกครั้งดังนั้นให้ทิ้งดัชนีที่มีอยู่ของ Colleciton ในตอนแรกและตอนนี้เมื่อคุณเรียกใช้พังพอนมันจะสร้างดัชนีใหม่ กระบวนการข้างต้นช่วยแก้ปัญหาของฉันได้


1

คุณยังสามารถแก้ไขปัญหานี้ได้โดยการทิ้งดัชนี

สมมติว่าคุณต้องการลบดัชนีเฉพาะออกจากคอลเลกชันusersและฟิลด์usernameพิมพ์สิ่งนี้:

db.users.dropIndex('username_1');


1

หากตาราง / คอลเลกชันว่างเปล่าให้สร้างดัชนีเฉพาะสำหรับฟิลด์:

db.<collection_name>.createIndex({'field':1}, {unique: true})

หากตาราง / คอลเลกชันไม่ว่างเปล่าให้วางคอลเล็กชันและสร้างดัชนี:

db.<collection_name>.drop()
db.<collection_name>.createIndex({'field':1}, {unique: true})

ตอนนี้รีสตาร์ท mongoDB


1

ตรวจสอบว่า autoIndex ใน schema เป็นจริงอาจตั้งค่าเป็นเท็จ (ค่าเริ่มต้นจริง) เมื่อคุณใช้ตัวเลือก mongoose.connect


1

ฉันประสบปัญหาเดียวกันมาระยะหนึ่งแล้วและทำการค้นหามากมายและวิธีแก้ปัญหาสำหรับฉันคือcreateIndexes()ฟังก์ชัน

ฉันหวังว่าจะช่วยได้

ดังนั้นโค้ดจะเป็นแบบนั้น

User = new Schema ({
   email: {type: String, unique: true}
});
User.createIndexes();

0

หากคุณกำลังใช้ตัวเลือกautoIndex: falseในวิธีการเชื่อมต่อดังนี้:

mongoose.connect(CONNECTION_STRING, { autoIndex: false });

ลองลบออก หากไม่ได้ผลให้ลองรีสตาร์ท mongodbตามที่แนะนำในชุดข้อความนี้


0

คุณสามารถกำหนดสคีมาของคุณเป็น

User = new Schema ({
  email: {
      type: String,
      unique: true
  }
})

แต่อาจจะใช้ไม่ได้เมื่อมีเอกสารอยู่แล้วและหลังจากนั้นคุณได้เปลี่ยนสคีมาของผู้ใช้ คุณสามารถสร้างดัชนีบนอีเมลสำหรับคอลเล็กชันผู้ใช้นี้ได้หากคุณไม่ต้องการทิ้งคอลเล็กชัน ใช้คำสั่งนี้คุณสามารถสร้างดัชนีบนอีเมลได้

db.User.createIndex({email:1},{unique: true})

หรือคุณสามารถวางคอลเล็กชันแล้วเพิ่มผู้ใช้อีกครั้ง
สำหรับการทิ้งคอลเลกชันคุณสามารถป้อนสิ่งนี้:

db.User.drop()

0

เมื่อฉันพบปัญหานี้ฉันได้ลองทิ้งฐานข้อมูลเริ่มต้นเซิร์ฟเวอร์ใหม่ (nodemon) หลายครั้งและไม่มีเทคนิคใดที่ใช้ไม่ได้เลย ฉันพบวิธีแก้ปัญหาต่อไปนี้ผ่าน Robo 3T:

  1. ใน Robo 3T ดับเบิลคลิกที่ฐานข้อมูลเพื่อเปิดคอลเลกชัน
  2. เปิดคอลเล็กชันเพื่อเปิดเผยคอลเล็กชันที่มีปัญหา ตรวจสอบให้แน่ใจว่าคอลเล็กชันของคุณว่างเปล่าเพื่อเริ่มต้นด้วย
  3. คลิกขวาที่โฟลเดอร์ Indexes ตามค่าเริ่มต้นคุณจะเห็น_id_เป็นค่าเริ่มต้น ตอนนี้เลือกเพิ่มดัชนี
  4. เลือกชื่อพูดemailสำหรับฟิลด์อีเมลเช่น
  5. ระบุคีย์เป็น JSON ตัวอย่างเช่น

    {
       "email": 1
    }
    
  6. คลิกที่ช่องทำเครื่องหมายเฉพาะ

  7. บันทึก

เพื่อให้แน่ใจว่าจะไม่มีการบันทึกอีเมลซ้ำใน MongoDB


ความหมายของ 1 ในออบเจ็กต์ {"email": 1} คืออะไร?
siluveru kiran kumar

0

ตรวจสอบให้แน่ใจว่าคอลเล็กชันของคุณไม่มีฟิลด์ซ้ำซ้อนที่คุณเพิ่งใส่ดัชนีเฉพาะ

จากนั้นรีสตาร์ทแอปของคุณ (พังพอน) เพียงแค่เพิ่มดัชนีอย่างเงียบ ๆ ล้มเหลว


0

การนำเอกสารทั้งหมดออกจากคอลเล็กชัน:

db.users.remove({})

และการรีสตาร์ทตามที่คนอื่นกล่าวถึงก็ใช้ได้ผลสำหรับฉัน


0

หาก MongoDB ของคุณทำงานเป็นบริการ (วิธีง่ายๆในการค้นหาสิ่งนี้คือหากคุณไม่จำเป็นต้องเชื่อมต่อกับฐานข้อมูลโดยไม่ต้องเริ่มไฟล์ mongod.exe ผ่านเทอร์มินัล) หลังจากทำการเปลี่ยนแปลงแล้วคุณอาจต้องเริ่มบริการใหม่และ / หรือวางฐานข้อมูลของคุณอย่างสมบูรณ์

มันค่อนข้างแปลกเพราะสำหรับผู้ใช้บางคนเพียงแค่ปล่อยคอลเลกชั่นเดียวก็ใช้ได้แล้ว บางคนก็ต้องทิ้งฐานข้อมูล แต่สิ่งเหล่านั้นไม่ได้ผลสำหรับฉัน ฉันทิ้งฐานข้อมูลแล้วเริ่มบริการ MongoDB Server ใหม่

ในการเริ่มต้นบริการค้นหาบริการบนแถบค้นหาของ Windows จากนั้นค้นหาบริการ MongoDB ให้ดับเบิลคลิกเพื่อเปิดจากนั้นหยุดและเริ่มบริการอีกครั้ง

หากวิธีอื่นไม่ได้ผลสำหรับคุณฉันเชื่อว่าวิธีนี้จะได้ผล


0

ในกรณีของฉันพังพอนล้าสมัย ฉันตรวจสอบโดยการเรียกใช้ npm ล้าสมัยบน CMD และอัปเดต 'พังพอน'

โปรดบอกว่านั่นเหมาะกับคุณหรือไม่


คุณใช้เวอร์ชันอะไร
Baboo_

0

เมื่อคุณเชื่อมต่อฐานข้อมูลของคุณกับแอปพลิเคชันให้เพิ่มตัวเลือกนี้: "audoIndex: true" เช่นในรหัสของฉันฉันทำสิ่งนี้:

const options = {
// your options go here
...
// this code is the solution
audoIndex: true
}
mongoose.connect(DB_URI, options);

ฉันยังทิ้งคอลเล็กชันที่มีปัญหาและสร้างขึ้นใหม่เพื่อให้แน่ใจว่าจะใช้งานได้ ฉันพบวิธีแก้ปัญหานี้ที่: https://dev.to/emmysteven/solved-mongoose-unique-index-not-working-45d5 ฉันยังลองวิธีแก้ปัญหาเช่น "เริ่มต้น MongoDB" แต่ไม่ได้ผลสำหรับฉัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.