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?


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.


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()

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/


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
  }
);

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: { : \"martyna@martycud.com\" }"
    }
})

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


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


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.


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: 'old-email@example.com' },
      { email: 'new-email@example.com' },
      { 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.


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.


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.


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');


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.


1

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


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();

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.


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()

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.


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.


0

Alle Dokumente aus der Sammlung entfernen:

db.users.remove({})

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


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.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.