Mungo Einzigartiger Index funktioniert nicht!

88

Ich versuche, MongoDB einen doppelten Wert anhand seines Index erkennen zu lassen. Ich denke, dass dies in MongoDB möglich ist, aber durch den Mongoose-Wrapper scheinen die Dinge kaputt zu sein. Also für so etwas:

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

Ich kann 2 Benutzer mit derselben E-Mail speichern. Verflixt.

Das gleiche Problem wurde hier zum Ausdruck gebracht: https://github.com/LearnBoost/mongoose/issues/56 , aber dieser Thread ist alt und führt zu nichts.

Im Moment rufe ich die Datenbank manuell an, um den Benutzer zu finden. Dieser Anruf ist nicht teuer, da "E-Mail" indiziert ist. Aber es wäre trotzdem schön, wenn es nativ gehandhabt würde.

Hat jemand eine Lösung dafür?

foobar
quelle
1
Schlechte Nachrichten, es ist immer noch ein Problem mit Mongod v2.4.3, Mungo v3.6.20
Damphat
Unique scheint auf einem meiner Hosts zu funktionieren, erzwingt jedoch keine Uniques mit genau demselben Knoten- / Mungo-Code auf einem anderen Host. Auf dem Host, der ordnungsgemäß funktioniert, wird Single Mongod 3.4.10 ausgeführt, auf dem Host, auf dem kein Replikatset mit Mongod 3.2.17 ausgeführt wird. Auf beiden Hosts erstelle ich eine Sammlung von Grund auf neu, sodass die vorhandenen Dups kein Problem darstellen. Ich habe die meisten Lösungen auf dieser Seite ausprobiert und die funktionierende war Mungo-Unique-Validator von @Isaac Pak.
Maksym

Antworten:

91

Hoppla! Sie müssen nur Mongo neu starten.

foobar
quelle
4
Ich habe das gleiche Problem, kann aber nicht herausfinden, wie Mongo unter OSX neu gestartet werden kann. Wenn ich den Prozess abbreche, wird er automatisch wieder erzeugt und der eindeutige Index funktioniert immer noch nicht ... irgendwelche Ideen?
Ragulka
7
Was meinst du mit "Ups, du musst nur Mongo neu starten"?! Wollen Sie damit sagen, dass es unmöglich ist, einen Index hinzuzufügen, ohne die Datenbank herunterzufahren?
Andrewrk
7
Das ist nicht wahr. Sie müssen mongo nicht neu starten, um einen Index hinzuzufügen.
JohnnyHK
1
für die einzigartige Sache .. Ich musste Mongo neu starten .. und es hat funktioniert .. Danke!
Muhammad Ahsan Ayaz
2
Ich habe versucht, neu zu starten. Auch neu indizieren. Musste die Datenbank löschen, um dies zu beheben. Vermutlich gab es vor dem Hinzufügen des Index bereits Duplikate, sodass ich in einer Produktionsdatenbank Duplikate entfernen und dann neu starten müsste.
Isimmons
39

Hoppla! Sie müssen nur Mongo neu starten.

Und auch neu indizieren mit:

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

Da ich keine wichtigen Daten habe, können Sie beim Testen auch Folgendes tun:

mongo <db-name>
> db.dropDatabase()
jpillora
quelle
12
db.dropDatabase () löscht Ihre Datenbank!
Isaac Pak
27

Ich bin auf dasselbe Problem gestoßen : Ich habe die eindeutige Einschränkung für das emailFeld zu unserem UserSchemahinzugefügt, nachdem ich bereits Benutzer zur Datenbank hinzugefügt hatte, und konnte Benutzer weiterhin mit betrogenen E-Mails speichern. Ich habe dies folgendermaßen gelöst:

1) Entfernen Sie alle Dokumente aus der Benutzersammlung.

2) Führen Sie in der Mongo-Shell den folgenden Befehl aus: db.users.createIndex({email: 1}, {unique: true})

Beachten Sie in Bezug auf Schritt 1 Folgendes aus Mongos Dokumenten:

MongoDB kann keinen eindeutigen Index für die angegebenen Indexfelder erstellen, wenn die Sammlung bereits Daten enthält, die die eindeutige Einschränkung für den Index verletzen würden.

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

Neil Strain
quelle
11

Dieses Verhalten tritt auch auf, wenn Sie in Mongo einige Duplikate hinterlassen haben. Mongoose wird versuchen, sie in Mongo zu erstellen, wenn Ihre Anwendung gestartet wird.

Um dies zu verhindern, können Sie diesen Fehler folgendermaßen behandeln:

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

Ok, ich konnte dies aus der Mongoshell heraus beheben, indem ich den Index für das Feld hinzufügte und die eindeutige Eigenschaft festlegte:

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

Shell sollte folgendermaßen reagieren:

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

Nun, um schnell von der Mongoshell zu testen:

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

Sollte geben: WriteResult ({"nInserted": 1})

Aber wenn Sie noch einmal wiederholen:

db.<collectionName>.insert(doc)

Wird geben:

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

Ich habe so etwas gemacht:

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

Ich habe die Foo.createIndexes()Zeile hinzugefügt , da beim Ausführen des Codes die folgende Warnung angezeigt wurde:

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

Ich bin nicht sicher, ob Foo.createIndexes()es asynchron ist, aber AFAIK-Dinge scheinen gut zu funktionieren

Sonnenwende333
quelle
Die einzige Antwort auf die Frage, die das Problem anspricht, anstatt sich darum zu drehen.
Saksham Gupta
Diese Antwort hat mir geholfen. Mir fehlte lediglich die index: trueErstellung meines eindeutigen Index.
Elcid
6

Laut Dokumentation: https://docs.mongodb.com/v2.6/tutorial/modify-an-index/

Um einen vorhandenen Index zu ändern, müssen Sie den Index löschen und neu erstellen.

MONGO NICHT NEU STARTEN!

1 - Löschen Sie die Sammlung

db.users.drop()

2 - Indizieren Sie die Tabelle neu

db.users.ensureIndex({email: 1, type: 1}, {unique: true})
Damien Romito
quelle
Es heißt Drop Index nicht die Sammlung
Zero0Ho
5

Mungo ist etwas locker, wenn eindeutige Indizes auf Anwendungsebene erzwungen werden. Daher wird es bevorzugt, entweder Ihre eindeutigen Indizes mithilfe der Mongo-Cli aus der Datenbank selbst zu erzwingen oder Mungo explizit mitzuteilen, dass Sie den uniqueIndex ernst nehmen, indem Sie die folgende Codezeile direkt nach Ihrem UserSchema schreiben:

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

Dadurch wird der eindeutige Index sowohl für usernameals auch für emailFelder in Ihrem UserSchema erzwungen. Prost.

Moeabdol
quelle
5
Ein bisschen spät zur Party, aber was
nützt
Was nützen herabwürdigende Kommentare, die in keiner Weise helfen. Diese Lösung ist solide und produktionsbereit.
Isaac Pak
3

Mungo-Unique-Validator

So verwenden Sie dieses Plugin:

1) npm install - Mungo-Unique-Validator speichern

2) Befolgen Sie in Ihrem Schema diese Anleitung:

// 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) Mungo-Methoden

Wenn Sie Methoden wie diese verwenden, müssen findOneAndUpdateSie dieses Konfigurationsobjekt übergeben:

{ runValidators: true, context: 'query' }

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

4) zusätzliche Optionen

  1. Groß- und Kleinschreibung nicht berücksichtigen

    Verwenden Sie die Option uniqueCaseInsensitive in Ihrem Schema

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

  2. benutzerdefinierte Fehlermeldungen

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

Jetzt können Sie die eindeutige Eigenschaft zu Ihren Schemas hinzufügen / löschen, ohne sich Gedanken über einen Neustart von Mongo, das Löschen von Datenbanken oder das Erstellen von Indizes machen zu müssen.

Vorsichtsmaßnahmen (aus den Dokumenten):

Da wir uns auf asynchrone Operationen verlassen, um zu überprüfen, ob ein Dokument in der Datenbank vorhanden ist, können zwei Abfragen gleichzeitig ausgeführt werden. Beide erhalten 0 zurück und werden dann beide in MongoDB eingefügt.

Außer dem automatischen Sperren der Sammlung oder dem Erzwingen einer einzelnen Verbindung gibt es keine echte Lösung.

Für die meisten unserer Benutzer ist dies kein Problem, aber ein Randfall, den Sie beachten sollten.

Isaac Pak
quelle
3

Mungo kann stillschweigend keinen eindeutigen Index hinzufügen, wenn:

  1. Die Sammlung hat bereits einen gleichnamigen Index
  2. Die Sammlung enthält bereits Dokumente mit Duplikaten des indizierten Feldes

Listen Sie im ersten Fall die Indizes mit auf db.collection.getIndexes()und löschen Sie den alten Index mit db.collection.dropIndex("index_name"). Wenn Sie die Mongoose-Anwendung neu starten, sollte der neue Index korrekt hinzugefügt werden.

Im zweiten Fall müssen Sie die Duplikate entfernen, bevor Sie die Mongoose-Anwendung neu starten.

Derek Hill
quelle
2

Neueste Antwort: Mongodb muss überhaupt nicht neu gestartet werden. Wenn Colleciton bereits gleichnamige Indizes hat, erstellt Mongoose Ihre Indizes nicht erneut. Löschen Sie also zuerst die vorhandenen Indizes von Colleciton. Wenn Sie Mungo ausführen, wird ein neuer Index erstellt Der obige Prozess hat mein Problem gelöst.

Chen Jacky
quelle
1

Sie können dieses Problem auch beheben, indem Sie den Index löschen.

Nehmen wir an, Sie möchten den eindeutigen Index aus Sammlung usersund Feld entfernen. Geben Sie Folgendes ein username:

db.users.dropIndex('username_1');

Ademola Adegbuyi
quelle
1

Wenn die Tabelle / Sammlung leer ist, erstellen Sie einen eindeutigen Index für das Feld:

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

Wenn die Tabelle / Sammlung nicht leer ist, löschen Sie die Sammlung und erstellen Sie einen Index:

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

Starten Sie nun mongoDB neu.

Rakin Afser
quelle
1

Überprüfen Sie, ob autoIndex im Schema true ist. Wenn Sie die Optionen mongoose.connect verwenden, wird möglicherweise false (Standardwert true) festgelegt

Lee Quinze
quelle
1

Ich hatte eine Weile mit dem gleichen Problem zu kämpfen und viel gesucht, und die Lösung für mich war die createIndexes()Funktion.

Ich wünschte, das hilft.

Der Code wird also so sein.

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

Wenn Sie die Option autoIndex: falsein der Verbindungsmethode wie folgt verwenden:

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

Versuchen Sie, das zu entfernen. Wenn das nicht funktioniert, starten Sie mongodb neu, wie in diesem Thread vorgeschlagen.

Rafael Mejía
quelle
0

Sie können Ihr Schema als definieren

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

Aber vielleicht funktioniert dies nicht, wenn bereits ein Dokument vorhanden ist und Sie danach das Schema des Benutzers geändert haben. Sie können einen E-Mail-Index für diese Benutzersammlung erstellen, wenn Sie die Sammlung nicht löschen möchten. Mit diesem Befehl können Sie einen Index für E-Mails erstellen.

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

Oder Sie können die Sammlung einfach löschen und den Benutzer erneut hinzufügen.
Zum Löschen der Sammlung können Sie Folgendes eingeben:

db.User.drop()
Pulkit Aggarwal
quelle
0

Als ich auf dieses Problem stieß, habe ich versucht, die Datenbank zu löschen und den Server (nodemon) viele Male neu zu starten, und keiner der Tricks hat überhaupt nicht funktioniert. Ich habe über Robo 3T die folgende Lösung gefunden:

  1. Doppelklicken Sie im Robo 3T auf die Datenbank, um die Sammlungen zu öffnen
  2. Öffnen Sie die Sammlungen, um die betreffende Sammlung anzuzeigen. Stellen Sie zunächst sicher, dass Ihre Sammlungen leer sind
  3. Klicken Sie mit der rechten Maustaste auf den Indexordner. Standardmäßig wird das _id_als Standard angezeigt. Wählen Sie nun Index hinzufügen
  4. Wählen Sie einen Namen, z. B. emailfür das E-Mail-Feld
  5. Stellen Sie Schlüssel als JSON bereit. Beispielsweise

    {
       "email": 1
    }
  6. Klicken Sie auf das Kontrollkästchen Eindeutig

  7. sparen

Dadurch wird sichergestellt, dass keine doppelten E-Mails in der MongoDB gespeichert werden.

Balepur
quelle
Was bedeutet 1 hier im Objekt {"email": 1}?
Siluveru Kiran Kumar
0

Stellen Sie sicher, dass in Ihrer Sammlung das Feld, auf das Sie gerade den eindeutigen Index gesetzt haben, nicht redundant ist.

Dann starten Sie einfach Ihre App (Mungo) neu. Das Hinzufügen eines Index schlägt nur stillschweigend fehl.

Zero0Ho
quelle
0

Alle Dokumente aus der Sammlung entfernen:

db.users.remove({})

Und ein Neustart hat, wie andere sagten, für mich funktioniert

StefanBob
quelle
0

Wenn Ihre MongoDB als Dienst arbeitet (eine einfache Möglichkeit, dies zu finden, besteht darin, dass Sie keine Verbindung zur Datenbank herstellen müssen, ohne die Datei mongod.exe über das Terminal zu starten), müssen Sie den Dienst nach den Änderungen möglicherweise neu starten und / oder löschen Sie Ihre Datenbank vollständig.

Es ist ziemlich seltsam, weil für einige Benutzer nur das Löschen einer einzelnen Sammlung funktioniert hat. Einige von ihnen mussten nur die Datenbank löschen. Aber die haben bei mir nicht funktioniert. Ich habe die Datenbank gelöscht und dann den MongoDB Server-Dienst neu gestartet.

Um einen Dienst für die Dienstsuche in der Windows-Suchleiste neu zu starten und dann den MongoDB-Dienst zu finden, doppelklicken Sie zum Öffnen, stoppen Sie den Dienst und starten Sie ihn erneut.

Wenn die anderen Methoden bei Ihnen nicht funktioniert haben, wird dies meiner Meinung nach den Job machen.

Nick
quelle