Mongoose Unique indeksi çalışmıyor!


95

MongoDB'nin dizinine dayalı olarak yinelenen bir değer tespit etmesine izin vermeye çalışıyorum. Bunun MongoDB'de mümkün olduğunu düşünüyorum, ancak Mongoose ambalajı sayesinde işler bozuluyor gibi görünüyor. Yani bunun gibi bir şey için:

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

Aynı e-posta ile 2 kullanıcıyı kurtarabilirim. Lanet olsun.

Aynı sorun burada ifade edilmiştir: https://github.com/LearnBoost/mongoose/issues/56 , ancak bu ileti dizisi eski ve hiçbir yere götürmüyor.

Şimdilik, kullanıcıyı bulmak için veritabanına manuel olarak bir arama yapıyorum. Bu çağrı, "e-posta" dizine eklendiği için pahalı değil. Ama yine de yerel olarak ele alınmasına izin vermek güzel olurdu.

Kimsenin buna bir çözümü var mı?


1
Kötü haber, hala mongod v2.4.3, mongoose v3.6.20 ile ilgili sorun
damphat

Unique, ana bilgisayarlarımdan birinde çalışıyor gibi görünüyor, ancak farklı bir ana bilgisayarda tam olarak aynı düğüm / firavun faresi kodunu kullanarak benzersizleri zorlayamıyor. Düzgün çalışan ana bilgisayar, mongod 3.2.17 ile çoğaltma kümesini çalıştırmayan tek mongod 3.4.10'u çalıştırır. Bu sayfadaki çözümlerin çoğunu denedim ve işe yarayan @Isaac Pak'tan mongoose-benzersiz-doğrulayıcıydı.
Maksym

Yanıtlar:


95

Oops! Sadece mongo'yu yeniden başlatmanız gerekiyor.


4
Aynı sorunu yaşıyorum, ancak OSX'te mongo'yu nasıl yeniden başlatacağımı bulamıyorum. Süreci sonlandırdığımda, otomatik olarak yeniden ortaya çıkacak ve benzersiz dizin hala çalışmıyor ... herhangi bir fikir?
ragulka

7
Ne demek "oops mongo'yu yeniden başlatmalısın" ?! Veritabanını indirmeden bir dizin eklemenin imkansız olduğunu mu söylüyorsunuz?
andrewrk

7
Bu doğru değil. Bir dizin eklemek için mongo'yu yeniden başlatmanıza gerek yoktur.
JohnnyHK

1
eşsiz şey için .. mongo'yu yeniden başlatmam gerekiyordu .. ve işe yaradı .. Teşekkürler!
Muhammad Ahsan Ayaz

2
Yeniden başlatmayı denedim. Ayrıca yeniden dizin oluşturuyor. Bunu çözmek için veritabanını bırakmak zorunda kaldım. Sorunu tahmin etmek, dizini eklemeden önce kopyaların zaten mevcut olmasıdır, bu nedenle bir üretim veritabanında kopyaları kaldırmam ve ardından yeniden başlatmam gerekir mi?
isimmons

40

Oops! Sadece mongo'yu yeniden başlatmanız gerekiyor.

Ve aşağıdakilerle de yeniden dizine ekleyin:

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

Test sırasında, önemli verilerim olmadığı için şunları da yapabilirsiniz:

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

16
db.dropDatabase () veritabanınızı siler!
Isaac Pak

28

Aynı sorunla karşılaştım: Kullanıcıları db'ye zaten ekledikten sonra emailalan için benzersiz kısıtlamayı UserSchemaekledim ve yine de kullanıcıları çift e-postalarla kurtarabildim. Bunu aşağıdakileri yaparak çözdüm:

1) Kullanıcı koleksiyonundaki tüm belgeleri kaldırın.

2) Mongo kabuğundan şu komutu yürütün: db.users.createIndex({email: 1}, {unique: true})

1. adımla ilgili olarak, Mongo'nun belgelerinden şunları unutmayın:

Koleksiyon zaten dizin için benzersiz kısıtlamayı ihlal edecek veriler içeriyorsa, MongoDB belirtilen dizin alanlarında benzersiz bir dizin oluşturamaz.

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


11

Bu davranış, Mongo'da bazı kopyalar bıraktığınızda da gerçekleşir. Mongoose, uygulamanız başladığında bunları Mongo'da oluşturmaya çalışacaktır.

Bunu önlemek için bu hatayı şu şekilde halledebilirsiniz:

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

10

Tamam, alana dizini ekleyerek ve benzersiz özelliği ayarlayarak bunu mongoshell'den çözebildim:

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

Shell şu şekilde yanıt vermelidir:

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

Şimdi mongoshell'den hızlıca test etmek için:

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

Verilmesi gereken: WriteResult ({"nInserted": 1})

Ama tekrarlarken:

db.<collectionName>.insert(doc)

Verecek:

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

Bunun gibi bir şey yaptım:

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()Kod çalıştırılırken aşağıdaki kullanımdan kaldırma uyarısını aldığım bc satırını ekledim :

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

Zaman Foo.createIndexes()uyumsuz olup olmadığından emin değilim , ancak AFAIK şeyler iyi çalışıyor gibi görünüyor


Sorunun etrafında dönmekten çok soruna hitap eden sorunun tek cevabı.
Saksham Gupta

Bu cevap bana yardımcı oldu. Tek eksik olduğum, index: truebenzersiz indeksimin oluşturulmasıydı.
elcid


5

Mongoose, uygulama seviyesinden benzersiz indeksler uygularken biraz gevşektir; bu nedenle, mongo klibini kullanarak veritabanının kendisinden benzersiz endekslerinizi zorunlu kılmak veya uniqueUserSchema'nızdan hemen sonra aşağıdaki kod satırını yazarak mongoose'a dizin konusunda ciddi olduğunuzu açıkça belirtmek tercih edilir:

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

Bu, UserSchema'nızdaki hem usernameve hem de emailalanlarda benzersiz dizini zorlayacaktır. Şerefe.


5
Partiye biraz geç, ancak "benzersiz endeksleri uygularken biraz gevşek" olan bir
ORM'nin

Hiçbir şekilde yardımcı olmayan küçümseyici yorumlar ne işe yarar. Bu çözüm sağlam ve üretime hazır.
Isaac Pak

4

Mongoose, aşağıdaki durumlarda benzersiz bir dizin eklemekte sessizce başarısız olur:

  1. Koleksiyon zaten aynı adda bir dizine sahip
  2. Koleksiyon zaten, dizine alınmış alanın kopyalarına sahip belgeler içeriyor

İlk durumda, dizinleri ile listeleyin db.collection.getIndexes()ve eski dizini bırakındb.collection.dropIndex("index_name") . Mongoose uygulamasını yeniden başlattığınızda, yeni dizini doğru şekilde eklemesi gerekir.

İkinci durumda, Mongoose uygulamasını yeniden başlatmadan önce kopyaları kaldırmanız gerekir.


3

firavun faresi-benzersiz-doğrulayıcı

Bu eklenti nasıl kullanılır:

1) npm yüklemesi - mongoose-benzersiz-doğrulayıcıyı kaydedin

2) şemanızda bu kılavuzu izleyin:

// 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) firavun faresi yöntemleri

findOneAndUpdateSizin gibi yöntemleri kullanırken bu yapılandırma nesnesini iletmeniz gerekecektir:

{ runValidators: true, context: 'query' }

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

4) ek seçenekler

  1. büyük / küçük harfe duyarlı değil

    şemanızda uniqueCaseInsensitive seçeneğini kullanın

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

  2. özel hata mesajları

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

Artık, mongo'yu yeniden başlatma, veritabanlarını bırakma veya dizin oluşturma konusunda endişelenmeden şemalarınıza benzersiz özelliği ekleyebilir / silebilirsiniz.

Uyarılar (dokümanlardan):

Veritabanında bir belgenin var olup olmadığını doğrulamak için zaman uyumsuz işlemlere güvendiğimizden, aynı anda iki sorgunun yürütülmesi mümkündür, her ikisi de 0'ı geri alır ve ardından her ikisi de MongoDB'ye eklenir.

Koleksiyonu otomatik olarak kilitlemenin veya tek bir bağlantıyı zorlamanın dışında gerçek bir çözüm yoktur.

Kullanıcılarımızın çoğu için bu bir sorun olmayacak, ancak dikkat edilmesi gereken bir uç durumdur.


2

En yeni cevap: mongodb'yi yeniden başlatmaya hiç gerek yok, eğer colleciton zaten aynı isim indekslerine sahipse, mongoose indekslerinizi tekrar oluşturmayacaktır, bu yüzden önce colleciton'ın mevcut indekslerini bırakın ve şimdi, firavun faresini çalıştırdığınızda yeni indeks oluşturacaktır. , yukarıdaki süreç sorunumu çözdü.


1

Bu sorunu ayrıca dizini bırakarak da çözebilirsiniz;

benzersiz dizini koleksiyondan usersve alandan kaldırmak istediğinizi varsayalım username, şunu yazın:

db.users.dropIndex('username_1');


1

Tablo / koleksiyon boşsa, alan için benzersiz bir dizin oluşturun:

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

Tablo / koleksiyon boş değilse, koleksiyonu bırakın ve dizin oluşturun:

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

Şimdi mongoDB'yi yeniden başlatın.


1

şemadaki autoIndex'in doğru olup olmadığını kontrol edin, mongoose.connect seçeneklerini kullandığınızda belki false (varsayılan doğru) olarak ayarlanır


1

Bir süre aynı sorunla karşılaştım ve çok fazla arama yaptım ve benim için çözüm createIndexes()işlevdi.

Bunun yardımcı olmasını dilerim.

bu yüzden kod böyle olacak.

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

0

autoIndex: falseBağlantı yöntemindeki seçeneği şu şekilde kullanıyorsanız :

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

Kaldırmayı dene. Bu işe yaramazsa, bu ileti dizisinde önerilen birçok kişinin mongodb'u yeniden başlatmayı deneyin .


0

Şemanızı şu şekilde tanımlayabilirsiniz:

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

Ama belki zaten bir belge varken bu işe yaramayacaktır ve bundan sonra Kullanıcının şemasını değiştirdiniz. Koleksiyonu bırakmak istemiyorsanız, bu Kullanıcı koleksiyonu için e-postada bir dizin oluşturabilirsiniz. Bu komutu kullanarak e-postada bir dizin oluşturabilirsiniz.

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

Veya koleksiyonu bırakıp kullanıcıyı tekrar ekleyebilirsiniz.
Koleksiyonu düşürmek için şunu girebilirsiniz:

db.User.drop()

0

Bu sorunla karşılaştığımda, veritabanını bırakmayı, sunucuyu (nodemon) birçok kez yeniden başlatmayı denedim ve hiçbir numara çalışmadı. Robo 3T aracılığıyla aşağıdaki çalışmaları buldum:

  1. Robo 3T'de, koleksiyonları açmak için Veritabanına çift tıklayın
  2. Söz konusu Koleksiyonu ortaya çıkarmak için koleksiyonları açın. Başlamak için koleksiyonlarınızın boş olduğundan emin olun
  3. Dizinler Klasörüne sağ tıklayın. Varsayılan _id_olarak, varsayılan olarak göreceksiniz . Şimdi, Dizin Ekle'yi seçin
  4. emailÖrneğin e-posta alanı için bir isim seçin
  5. Anahtarları JSON olarak sağlayın. Örneğin

    {
       "email": 1
    }
    
  6. Benzersiz onay kutusunu tıklayın

  7. Kayıt etmek

Bu, MongoDB'ye yinelenen e-postaların kaydedilmemesini sağlayacaktır.


{"email": 1} nesnesindeki 1'in anlamı nedir?
siluveru kiran kumar

0

Koleksiyonunuzda, benzersiz dizini koyduğunuz alanın fazlalığı olmadığından emin olun.

Ardından uygulamanızı (firavun faresi) yeniden başlatın. Sadece sessizce dizin ekleme başarısız olur.


0

Koleksiyondan tüm belgelerin kaldırılması:

db.users.remove({})

Ve başkalarının da bahsettiği gibi yeniden başlatma benim için çalıştı


0

MongoDB'niz bir hizmet olarak çalışıyorsa (bunu bulmanın kolay yolu, terminal aracılığıyla mongod.exe dosyasını başlatmadan veritabanına bağlanmanız gerekmemesidir), değişiklikleri yaptıktan sonra hizmeti yeniden başlatmanız gerekebilir ve / veya veritabanınızı tamamen bırakın.

Bu oldukça garip çünkü bazı kullanıcılar için tek bir koleksiyonu düşürmek işe yaradı. Bazılarının sadece veritabanını bırakması gerekiyordu. Ama bunlar benim için işe yaramadı. Veritabanını düşürdüm, ardından MongoDB Sunucu hizmetini yeniden başlattım.

Windows arama çubuğunda bir hizmet arama Hizmetlerini yeniden başlatmak ve ardından MongoDB hizmetini bulmak için çift tıklayarak açın, ardından durdurun ve hizmeti yeniden başlatın.

Diğer yöntemler sizin için işe yaramadıysa, bunun işi yapacağına inanıyorum.


0

Benim durumumda firavun faresi modası geçmişti. CMD'de güncel olmayan npm çalıştırarak kontrol ettim. ve güncellenmiş "firavun faresi".

Lütfen bunun sizin için de işe yarayıp yaramadığını söyleyin.


Hangi sürümü kullanıyordunuz?
Baboo_

0

Veritabanınızı uygulamaya bağladığınızda şu seçeneği ekleyin: "audoIndex: true" örneğin koduma şunu yaptım:

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

Ayrıca sorun yaşadığım koleksiyonu da bıraktım ve çalışacağından emin olmak için yeniden oluşturdum. Bu çözümü şu adreste buldum: https://dev.to/emmysteven/solved-mongoose-unique-index-not-working-45d5 Ayrıca "MongoDB'yi yeniden başlat" gibi çözümleri de denedim ama işime yaramadı.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.