Indeks unik Mongoose tidak berfungsi!

95

Saya mencoba membiarkan MongoDB mendeteksi nilai duplikat berdasarkan indeksnya. Saya pikir ini mungkin terjadi di MongoDB, tetapi melalui pembungkus Mongoose hal-hal tampaknya rusak. Jadi untuk sesuatu seperti ini:

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

Saya dapat menyelamatkan 2 pengguna dengan email yang sama. Menisik.

Masalah yang sama telah diungkapkan di sini: https://github.com/LearnBoost/mongoose/issues/56 , tetapi utas itu sudah lama dan tidak mengarah ke mana pun.

Untuk saat ini, saya secara manual melakukan panggilan ke db untuk menemukan pengguna. Panggilan itu tidak mahal karena "email" diindeks. Tapi akan menyenangkan membiarkannya ditangani secara asli.

Apakah ada yang punya solusi untuk ini?

foobar.dll
sumber
1
Berita buruk, masih ada masalah dengan mongod v2.4.3, mongoose v3.6.20
damphat
Unique tampaknya berfungsi pada salah satu host saya, tetapi gagal menerapkan keunikan menggunakan kode node / luwak yang sama persis pada host yang berbeda. Host yang bekerja dengan baik menjalankan single mongod 3.4.10, yang tidak - menjalankan replika yang disetel dengan mongod 3.2.17. Di kedua host, saya membuat koleksi dari awal, jadi dup yang ada tidak menjadi masalah. Saya telah mencoba sebagian besar solusi di halaman ini dan yang berhasil adalah validator-unik-luwak dari @Isaac Pak.
Maksym

Jawaban:

94

Ups! Anda hanya perlu memulai ulang mongo.

foobar.dll
sumber
4
Saya mengalami masalah yang sama, tetapi saya tidak dapat menemukan cara memulai ulang mongo di OSX. Ketika saya menghentikan proses, itu hanya akan muncul lagi secara otomatis dan indeks unik masih tidak berfungsi ... ada ide?
ragulka
7
apa maksudmu "oops kamu hanya perlu me-restart mongo" ?! apakah Anda mengatakan tidak mungkin menambahkan indeks tanpa menurunkan database?
andrewrk
7
Ini tidak benar. Anda tidak perlu memulai ulang mongo untuk menambahkan indeks.
JohnnyHK
1
untuk hal yang unik .. SAYA HARUS restart mongo .. dan berhasil .. Terima kasih!
Muhammad Ahsan Ayaz
2
Saya mencoba memulai ulang. Juga mengindeks ulang. Harus menjatuhkan database untuk mengatasi ini. Menebak masalahnya adalah bahwa duplikat sudah ada sebelum menambahkan indeks sehingga dalam db produksi saya perlu menghapus duplikat dan kemudian memulai ulang?
isimmons
40

Ups! Anda hanya perlu memulai ulang mongo.

Dan indeks ulang juga, dengan:

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

Dalam pengujian, karena saya tidak memiliki data penting, Anda juga dapat melakukan:

mongo <db-name>
> db.dropDatabase()
jpillora.dll
sumber
16
db.dropDatabase () menghapus database Anda!
Isaac Pak
28

Saya mengalami masalah yang sama: Saya menambahkan batasan unik untuk emailbidang tersebut ke kami UserSchemasetelah menambahkan pengguna ke db, dan masih dapat menyelamatkan pengguna dengan email penipuan. Saya menyelesaikan ini dengan melakukan hal berikut:

1) Hapus semua dokumen dari koleksi pengguna.

2) Dari shell mongo, jalankan perintah: db.users.createIndex({email: 1}, {unique: true})

Mengenai langkah 1, perhatikan bahwa dari dokumen Mongo:

MongoDB tidak dapat membuat indeks unik pada bidang indeks yang ditentukan jika koleksi sudah berisi data yang akan melanggar batasan unik untuk indeks tersebut.

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

Strain Neil
sumber
11

Perilaku ini juga terjadi jika Anda meninggalkan beberapa duplikat di Mongo. Mongoose akan mencoba membuatnya di Mongo saat aplikasi Anda dijalankan.

Untuk mencegahnya, Anda dapat menangani kesalahan ini dengan cara ini:

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

Oke, saya bisa menyelesaikan ini dari mongoshell dengan menambahkan indeks di lapangan dan mengatur properti unik:

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

Shell harus merespons dengan cara ini:

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

Sekarang untuk menguji dengan cepat dari mongoshell:

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

Harus memberikan: WriteResult ({"nInserted": 1})

Tapi saat mengulang lagi:

db.<collectionName>.insert(doc)

Akan memberi:

WriteResult({
    "nInserted" : 0,
    "writeError" : {
        "code" : 11000,
        "errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: fuelConsumption.users.$email_1  dup key: { : \"[email protected]\" }"
    }
})
woj.sierak
sumber
10

Saya telah melakukan sesuatu seperti ini:

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

Saya menambahkan Foo.createIndexes()baris bc. Saya mendapatkan peringatan penghentian berikut saat kode sedang dijalankan:

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

Saya tidak yakin apakah Foo.createIndexes()asynchronous, tetapi AFAIK tampaknya berfungsi dengan baik

titik balik matahari333
sumber
Satu-satunya jawaban untuk pertanyaan yang membahas masalah daripada berputar di sekitarnya.
Saksham Gupta
Jawaban ini membantu saya. Yang saya lewatkan hanyalah index: trueuntuk membuat indeks unik saya.
elcid
6

Menurut dokumentasi: https://docs.mongodb.com/v2.6/tutorial/modify-an-index/

Untuk mengubah indeks yang ada, Anda perlu melepaskan dan membuat ulang indeks.

JANGAN MULAI ULANG LAGU!

1 - jatuhkan koleksinya

db.users.drop()

2 - indeks ulang tabel

db.users.ensureIndex({email: 1, type: 1}, {unique: true})
Damien Romito
sumber
Dikatakan drop index bukan koleksi
Zero0Ho
5

Mongoose sedikit longgar saat menerapkan indeks unik dari level aplikasi; oleh karena itu, lebih disukai untuk menerapkan indeks unik Anda dari database itu sendiri menggunakan mongo cli atau secara eksplisit memberi tahu mongoose bahwa Anda serius tentang uniqueindeks dengan menulis baris kode berikut tepat setelah UserSchema Anda:

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

Ini akan memberlakukan indeks unik di kedua kolom usernamedan emaildi UserSchema Anda. Bersulang.

moeabdol.dll
sumber
5
Agak terlambat ke pesta, tapi yang bagus adalah ORM yang "sedikit longgar saat menerapkan indeks unik"
Imre_G
Apa gunanya meremehkan komentar yang tidak membantu dengan cara apa pun. Solusi ini solid dan siap produksi.
Isaac Pak
4

Mongoose diam-diam akan gagal menambahkan indeks unik jika:

  1. Koleksi sudah memiliki indeks dengan nama yang sama
  2. Koleksi sudah berisi dokumen dengan duplikat bidang yang diindeks

Dalam kasus pertama, daftarkan indeks dengan db.collection.getIndexes(), dan hapus indeks lama dengandb.collection.dropIndex("index_name") . Saat Anda memulai ulang aplikasi Mongoose, itu harus menambahkan indeks baru dengan benar.

Dalam kasus kedua, Anda perlu menghapus duplikat sebelum memulai ulang aplikasi Mongoose.

Derek Hill
sumber
3

luwak-unik-validator

Cara menggunakan plugin ini:

1) npm install --save mongoose-unique-validator

2) dalam skema Anda, ikuti panduan ini:

// 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) metode luwak

Saat menggunakan metode seperti findOneAndUpdateAnda harus meneruskan objek konfigurasi ini:

{ runValidators: true, context: 'query' }

ie. User.findOneAndUpdate(
      { email: '[email protected]' },
      { email: '[email protected]' },
      { runValidators: true, context: 'query' },
      function(err) {
        // ...
    }

4) opsi tambahan

  1. case insensitive

    gunakan opsi uniqueCaseInsensitive di skema Anda

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

  2. pesan kesalahan khusus

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

Sekarang Anda dapat menambahkan / menghapus properti unik ke skema Anda tanpa khawatir harus memulai ulang mongo, menjatuhkan database, atau membuat indeks.

Peringatan (dari dokumen):

Karena kami mengandalkan operasi asinkron untuk memverifikasi apakah sebuah dokumen ada dalam database, dua kueri dapat dieksekusi pada saat yang sama, keduanya mendapatkan 0 kembali, lalu keduanya dimasukkan ke dalam MongoDB.

Selain mengunci koleksi secara otomatis atau memaksa koneksi tunggal, tidak ada solusi nyata.

Bagi sebagian besar pengguna kami, ini tidak akan menjadi masalah, tetapi merupakan kasus tepi yang harus diperhatikan.

Isaac Pak
sumber
2

Jawaban terbaru: tidak perlu me-restart mongodb sama sekali, jika colleciton sudah memiliki indeks nama yang sama, luwak tidak akan membuat ulang indeks Anda lagi, jadi, jatuhkan indeks colleciton yang ada terlebih dahulu, dan sekarang, ketika Anda menjalankan mongoose, itu akan membuat indeks baru , proses di atas memecahkan masalah saya.

chen Jacky
sumber
1

Anda juga dapat mengatasi masalah ini dengan menghapus indeks;

anggaplah Anda ingin menghapus indeks unik dari collection usersdan field username, ketikkan ini:

db.users.dropIndex('username_1');

Ademola Adegbuyi
sumber
1

Jika tabel / koleksi kosong, buat indeks unik untuk bidang tersebut:

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

Jika tabel / koleksi tidak kosong, letakkan koleksi dan buat indeks:

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

Sekarang mulai ulang mongoDB.

Rakin Afser
sumber
1

periksa apakah autoIndex dalam skema benar, mungkin disetel salah (default benar) saat Anda menggunakan opsi mongoose.connect

Lee Quinze
sumber
1

Saya menghadapi masalah yang sama untuk sementara dan melakukan banyak pencarian dan solusi untuk saya adalah createIndexes()fungsinya.

Saya berharap itu membantu.

jadi kodenya akan seperti itu.

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

Jika Anda menggunakan opsi autoIndex: falsedalam metode koneksi seperti ini:

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

Coba hapus itu. Jika itu tidak berhasil, coba restart mongodb seperti yang disarankan di utas ini.

Rafael Mejía
sumber
0

Anda dapat menentukan skema Anda sebagai

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

Tetapi mungkin ini tidak akan berfungsi ketika sudah ada dokumen dan setelah itu, Anda telah mengubah skema Pengguna. Anda dapat membuat indeks pada email untuk Koleksi pengguna ini jika Anda tidak ingin menghapus koleksi. Dengan menggunakan perintah ini Anda dapat membuat indeks di email.

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

Atau Anda bisa melepaskan koleksi dan menambahkan pengguna lagi.
Untuk menjatuhkan koleksi, Anda dapat memasukkan ini:

db.User.drop()
Pulkit Aggarwal
sumber
0

Ketika saya mengalami masalah ini, saya mencoba menjatuhkan database, memulai ulang server (nodemon) berkali-kali dan tidak ada trik yang tidak berfungsi sama sekali. Saya menemukan pekerjaan berikut, melalui Robo 3T:

  1. Di Robo 3T, klik dua kali pada Database untuk membuka koleksi
  2. Buka koleksi untuk mengungkap Koleksi yang dimaksud. Pastikan koleksi Anda kosong, untuk memulai
  3. Klik kanan pada Folder Indeks. Secara default, Anda akan melihat file_id_ sebagai default. Sekarang, pilih Tambah Indeks
  4. Pilih nama, ucapkan email untuk bidang email, misalnya
  5. Berikan Kunci sebagai JSON. Sebagai contoh

    {
       "email": 1
    }
    
  6. Klik pada kotak centang Unik

  7. Menyimpan

Ini akan memastikan tidak ada email duplikat yang disimpan di MongoDB.

Balepur
sumber
apa arti dari 1 di sini di objek {"email": 1}?
siluveru kiran kumar
0

Pastikan koleksi Anda tidak memiliki bidang yang berlebihan tempat Anda baru saja memasukkan indeks unik.

Kemudian mulai ulang aplikasi Anda (luwak). Itu hanya diam-diam menambahkan indeks gagal.

Zero0Ho
sumber
0

Menghapus semua dokumen dari koleksi:

db.users.remove({})

Dan restart, seperti yang disebutkan orang lain, berhasil untuk saya

StefanBob
sumber
0

Jika MongoDB Anda berfungsi sebagai layanan (cara mudah menemukannya adalah jika Anda tidak perlu terhubung ke database tanpa memulai file mongod.exe melalui terminal), maka setelah melakukan perubahan, Anda mungkin perlu memulai ulang layanan dan / atau jatuhkan database Anda sepenuhnya.

Ini cukup aneh karena untuk beberapa pengguna hanya menjatuhkan satu koleksi yang berhasil. Beberapa dari mereka hanya perlu menjatuhkan database. Tapi itu tidak berhasil untuk saya. Saya menjatuhkan database, lalu memulai ulang layanan Server MongoDB.

Untuk memulai kembali Layanan, pencarian Layanan di bilah pencarian Windows kemudian temukan layanan MongoDB, klik dua kali untuk membuka lalu berhenti dan mulai layanan lagi.

Jika metode lain tidak berhasil untuk Anda, saya yakin ini akan berhasil.

nick
sumber
0

Dalam kasus saya, luwak sudah ketinggalan zaman. saya memeriksanya dengan menjalankan npm usang di CMD. dan memperbarui 'luwak'.

Tolong beri tahu apakah itu berhasil untuk Anda juga.

nishant srivastava
sumber
Versi apa yang Anda gunakan?
Baboo_
0

Ketika Anda menghubungkan database Anda dengan aplikasi, tambahkan opsi ini: "audoIndex: true" misalnya dalam kode saya, saya melakukan ini:

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

Saya juga membuang koleksi yang bermasalah dan membuatnya kembali untuk memastikannya berfungsi. Saya menemukan solusi ini di: https://dev.to/emmysteven/solved-mongoose-unique-index-not-working-45d5 Saya juga mencoba solusi seperti "restart MongoDB" tetapi tidak berhasil untuk saya.

Hasan
sumber