Indeks Mongoose Unique nie działa!


98

Próbuję pozwolić MongoDB wykryć zduplikowaną wartość na podstawie jej indeksu. Myślę, że jest to możliwe w MongoDB, ale przez opakowanie Mongoose wydaje się, że wszystko jest zepsute. Więc dla czegoś takiego:

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

Za pomocą tego samego adresu e-mail mogę zapisać 2 użytkowników. Cerować.

Ten sam problem został wyrażony tutaj: https://github.com/LearnBoost/mongoose/issues/56 , ale ten wątek jest stary i prowadzi donikąd.

Na razie ręcznie dzwonię do bazy danych, aby znaleźć użytkownika. To połączenie nie jest drogie, ponieważ „e-mail” jest indeksowany. Ale nadal byłoby miło pozwolić sobie na to natywnie.

Czy ktoś ma na to rozwiązanie?


1
Zła wiadomość, nadal jest problem z Mongod v2.4.3, Mongoose v3.6.20
damphat

Wydaje się, że Unique działa na jednym z moich hostów, ale nie udaje mu się wymusić unikatowych przy użyciu dokładnie tego samego kodu węzła / mangusty na innym hoście. Host, który działa poprawnie, uruchamia single mongod 3.4.10, ten który nie działa - uruchamia replikę ustawioną w mongod 3.2.17. Na obu hostach tworzę kolekcję od zera, więc istniejące dupki nie są problemem. Wypróbowałem większość rozwiązań na tej stronie, a tym, który działał, był walidator unikalnych mangust z @Isaac Pak.
Maksym

Odpowiedzi:


94

Ups! Musisz tylko zrestartować mongo.


4
Mam ten sam problem, ale nie mogę dowiedzieć się, jak ponownie uruchomić mongo na OSX. Kiedy zabiję proces, po prostu odrodzi się on automatycznie, a unikalny indeks nadal nie działa ... jakieś pomysły?
ragulka

7
co masz na myśli mówiąc "ups, musisz tylko zrestartować mongo" ?! czy twierdzisz, że nie można dodać indeksu bez wyłączenia bazy danych?
andrewrk

7
To nieprawda. Nie musisz ponownie uruchamiać mongo, aby dodać indeks.
JohnnyHK

1
za jedyną w swoim rodzaju rzecz .. MUSIAŁEM zrestartować mongo .. i zadziałało .. Dzięki!
Muhammad Ahsan Ayaz

2
Próbowałem uruchomić ponownie. Również reindeksowanie. Musiałem porzucić bazę danych, aby rozwiązać ten problem. Domyślam się, że problem polega na tym, że duplikaty istniały już przed dodaniem indeksu, więc w bazie produkcyjnej musiałbym usunąć duplikaty, a następnie ponownie uruchomić?
isimmons

40

Ups! Musisz tylko zrestartować mongo.

I ponownie zindeksuj, używając:

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

W testowaniu, ponieważ nie mam ważnych danych, możesz również:

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

16
db.dropDatabase () czyści twoją bazę danych!
Isaac Pak

28

Napotkałem ten sam problem: dodałem unikalne ograniczenie dla tego emailpola do naszego UserSchemapo dodaniu użytkowników do bazy danych i nadal byłem w stanie zapisywać użytkowników za pomocą podwójnych e-maili. Rozwiązałem to, wykonując następujące czynności:

1) Usuń wszystkie dokumenty z kolekcji użytkowników.

2) Z powłoki mongo wykonaj polecenie: db.users.createIndex({email: 1}, {unique: true})

Jeśli chodzi o krok 1, zwróć uwagę, że z dokumentów Mongo:

MongoDB nie może utworzyć unikatowego indeksu dla określonych pól indeksu, jeśli kolekcja zawiera już dane, które naruszałyby ograniczenie unikalności indeksu.

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


11

Takie zachowanie występuje również, jeśli zostawiłeś kilka duplikatów w Mongo. Mongoose spróbuje utworzyć je w Mongo podczas uruchamiania aplikacji.

Aby temu zapobiec, możesz obsłużyć ten błąd w następujący sposób:

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

10

Ok, udało mi się rozwiązać ten problem z mongoshell, dodając indeks na polu i ustawiając unikalną właściwość:

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

Shell powinien zareagować w ten sposób:

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

Teraz, aby szybko przetestować z mongoshell:

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

Powinien dać: WriteResult ({"nInserted": 1})

Ale powtarzając ponownie:

db.<collectionName>.insert(doc)

Da:

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

Zrobiłem coś takiego:

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

Dodałem Foo.createIndexes()wiersz bc Otrzymałem następujące ostrzeżenie o wycofaniu, gdy kod był uruchamiany:

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

Nie jestem pewien, czy Foo.createIndexes()jest asynchroniczny, ale wydaje się, że rzeczy AFAIK działają dobrze


Jedyna odpowiedź na pytanie, która dotyczy problemu, a nie obraca się wokół niego.
Saksham Gupta

Ta odpowiedź mi pomogła. Brakowało mi tylko tego, index: trueże mój unikalny indeks został utworzony.
elcid


6

Mongoose jest trochę luźny podczas wymuszania unikalnych indeksów z poziomu aplikacji; Dlatego preferowane jest wymuszanie unikalnych indeksów z samej bazy danych za pomocą mongo cli lub jawne poinformowanie mongoose, że poważnie podchodzisz do uniqueindeksu, pisząc następujący wiersz kodu tuż po UserSchema:

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

Będzie to egzekwować unikalny indeks na obu usernamei emailpól w UserSchema. Twoje zdrowie.


6
Trochę późno na imprezę, ale cóż to za ORM, który jest „trochę luźny, gdy
wymusza

Co dobrego z lekceważenia komentarzy, które w żaden sposób nie pomagają. To rozwiązanie solidne i gotowe do produkcji.
Isaac Pak

4

Mongoose po cichu nie doda unikalnego indeksu, gdy:

  1. Kolekcja ma już indeks o tej samej nazwie
  2. Kolekcja zawiera już dokumenty z duplikatami zindeksowanego pola

W pierwszym przypadku wypisz indeksy za pomocą db.collection.getIndexes()i usuń stary indeks za pomocą db.collection.dropIndex("index_name"). Po ponownym uruchomieniu aplikacji Mongoose powinna ona poprawnie dodać nowy indeks.

W drugim przypadku musisz usunąć duplikaty przed ponownym uruchomieniem aplikacji Mongoose.


3

walidator unikatowy-mangusty

Jak korzystać z tej wtyczki:

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

2) w swoim schemacie postępuj zgodnie z tym przewodnikiem:

// 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) metody mangusty

Podczas korzystania z metod takich jak findOneAndUpdatebędziesz musiał przekazać ten obiekt konfiguracyjny:

{ runValidators: true, context: 'query' }

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

4) opcje dodatkowe

  1. bez rozróżniania wielkości liter

    użyj opcji uniqueCaseInsensitive w swoim schemacie

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

  2. niestandardowe komunikaty o błędach

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

Teraz możesz dodawać / usuwać unikalną właściwość do swoich schematów bez martwienia się o ponowne uruchamianie mongo, usuwanie baz danych lub tworzenie indeksów.

Ostrzeżenia (z dokumentacji):

Ponieważ polegamy na operacjach asynchronicznych w celu sprawdzenia, czy dokument istnieje w bazie danych, możliwe jest wykonanie dwóch zapytań w tym samym czasie, oba zwracają 0, a następnie oba wstawiają do MongoDB.

Poza automatycznym blokowaniem kolekcji lub wymuszaniem pojedynczego połączenia nie ma prawdziwego rozwiązania.

Dla większości naszych użytkowników nie będzie to problemem, ale należy być tego świadomym.


2

Najnowsza odpowiedź: w ogóle nie ma potrzeby restartowania mongodb, jeśli colleciton ma już indeksy o tej samej nazwie, mongoose nie odtworzy ponownie twoich indeksów, więc najpierw upuść istniejące indeksy colleciton, a teraz, gdy uruchomisz mongoose, utworzy nowy indeks , powyższy proces rozwiązał mój problem.


1

Możesz również rozwiązać ten problem, upuszczając indeks;

załóżmy, że chcesz usunąć unikalny indeks z kolekcji usersi pola username, wpisz to:

db.users.dropIndex('username_1');


1

Jeśli tabela / kolekcja jest pusta, utwórz unikalny indeks dla pola:

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

Jeśli tabela / kolekcja nie jest pusta, usuń kolekcję i utwórz indeks:

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

Teraz zrestartuj mongoDB.


1

sprawdź, czy autoIndex w schemacie ma wartość true, może ustawić false (domyślnie true), gdy używasz opcji mongoose.connect


1

Przez jakiś czas miałem do czynienia z tym samym problemem i dużo szukałem, a rozwiązaniem dla mnie była createIndexes()funkcja.

Chciałbym, żeby to pomogło.

więc kod będzie taki.

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

0

Jeśli używasz opcji autoIndex: falsew metodzie połączenia takiej jak ta:

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

Spróbuj to usunąć. Jeśli to nie zadziała, spróbuj ponownie uruchomić mongodb, jak wiele sugeruje w tym wątku.


0

Możesz zdefiniować swój schemat jako

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

Ale może to nie zadziała, gdy istnieje już dokument, a potem zmieniłeś schemat użytkownika. Możesz utworzyć indeks wiadomości e-mail dla tej kolekcji użytkowników, jeśli nie chcesz porzucać tej kolekcji. Za pomocą tego polecenia możesz utworzyć indeks wiadomości e-mail.

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

Możesz też po prostu upuścić kolekcję i ponownie dodać użytkownika.
Aby upuścić kolekcję, możesz wprowadzić to:

db.User.drop()

0

Kiedy napotkałem ten problem, próbowałem wiele razy porzucić bazę danych, ponownie uruchomić serwer (nodemon) i żadna ze sztuczek w ogóle nie działała. Znalazłem następujące obejście, dzięki Robo 3T:

  1. W Robo 3T kliknij dwukrotnie bazę danych, aby otworzyć kolekcje
  2. Otwórz kolekcje, aby wyświetlić odpowiednią kolekcję. Na początek upewnij się, że Twoje kolekcje są puste
  3. Kliknij prawym przyciskiem myszy folder Indeksy. Domyślnie zobaczysz _id_jako domyślny. Teraz wybierz Dodaj indeks
  4. Wybierz nazwę email, na przykład pole e-mail
  5. Podaj klucze jako JSON. Na przykład

    {
       "email": 1
    }
    
  6. Kliknij pole wyboru Unikalne

  7. Zapisać

Dzięki temu w MongoDB nie zostaną zapisane żadne zduplikowane wiadomości e-mail.


jakie jest znaczenie 1 w obiekcie {"email": 1}?
siluveru kiran kumar

0

Upewnij się, że Twoja kolekcja nie zawiera dodatkowego pola, w którym właśnie umieściłeś unikalny indeks.

Następnie po prostu uruchom ponownie aplikację (mangusta). Po prostu dyskretnie dodaje indeks nie działa.


0

Usuwanie wszystkich dokumentów z kolekcji:

db.users.remove({})

I restart, jak wspominali inni, działał dla mnie


0

Jeśli Twoja baza danych MongoDB działa jako usługa (łatwy sposób na znalezienie tego polega na tym, że nie musisz łączyć się z bazą danych bez uruchamiania pliku mongod.exe przez terminal), to po wprowadzeniu zmian może być konieczne ponowne uruchomienie usługi i / lub całkowicie usuń bazę danych.

Jest to dość dziwne, ponieważ dla niektórych użytkowników po prostu upuszczenie jednej kolekcji zadziałało. Niektórzy z nich musieli po prostu usunąć bazę danych. Ale to nie zadziałało dla mnie. Porzuciłem bazę danych, a następnie ponownie uruchomiłem usługę MongoDB Server.

Aby ponownie uruchomić wyszukiwanie usług Usługi na pasku wyszukiwania systemu Windows, a następnie znajdź usługę MongoDB, kliknij dwukrotnie, aby ją otworzyć, a następnie zatrzymaj i uruchom ponownie usługę.

Jeśli inne metody nie zadziałały, wierzę, że to zadziała.


0

W moim przypadku mangusta była przestarzała. Sprawdziłem to, uruchamiając npm przestarzały na CMD. i zaktualizował „mangusta”.

Powiedz, czy to też zadziałało.


Jakiej wersji używasz?
Baboo_

0

Po połączeniu bazy danych z aplikacją dodaj opcję: "audoIndex: true" na przykład w moim kodzie zrobiłem tak:

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

Upuściłem też kolekcję, z którą mam problem i odtworzyłem ją, aby mieć pewność, że zadziała. Znalazłem to rozwiązanie pod adresem : https://dev.to/emmysteven/solved-mongoose-unique-index-not-working-45d5. Próbowałem również rozwiązań typu „restart MongoDB”, ale nie działały.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.