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?

foobar
źródło
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.

foobar
źródło
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()
jpillora
źródło
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/

Neil Strain
źródło
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
  }
);
Pierre Maoui
źródło
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: { : \"[email protected]\" }"
    }
})
woj.sierak
źródło
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

przesilenie 333
źródło
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

Zgodnie z dokumentacją: https://docs.mongodb.com/v2.6/tutorial/modify-an-index/

Aby zmodyfikować istniejący indeks, musisz go usunąć i ponownie utworzyć.

NIE URUCHAMIAJ PONOWNIE MONGO!

1 - upuść kolekcję

db.users.drop()

2 - ponownie zindeksuj tabelę

db.users.ensureIndex({email: 1, type: 1}, {unique: true})
Damien Romito
źródło
Mówi, że indeks upuszczania nie jest kolekcją
Zero0Ho,
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.

moeabdol
źródło
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.

Derek Hill
źródło
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: '[email protected]' },
      { email: '[email protected]' },
      { 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.

Isaac Pak
źródło
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.

chen Jacky
źródło
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');

Ademola Adegbuyi
źródło
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.

Rakin Afser
źródło
1

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

Lee Quinze
źródło
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();
Samir Hosny
źródło
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.

Rafael Mejía
źródło
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()
Pulkit Aggarwal
źródło
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.

Balepur
źródło
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.

Zero0Ho
źródło
0

Usuwanie wszystkich dokumentów z kolekcji:

db.users.remove({})

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

StefanBob
źródło
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.

nacięcie
źródło
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.

nishant srivastava
źródł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.

Hasan
źródło