2013-05-03 3 views
75

wie der Titel sagt, ich möchte eine Suche (eins) für ein Dokument, durch _id, und wenn nicht existiert, haben es erstellt , ob es gefunden wurde oder erstellt wurde, wurde es im Callback zurückgegeben.MongoDB atomic "findOrCreate": findOne, einfügen, wenn nicht vorhanden, aber nicht aktualisieren

Ich möchte es nicht aktualisieren, wenn es existiert, wie ich findAndModify gelesen habe. Ich habe viele andere Fragen zu Stackoverflow in diesem Zusammenhang gesehen, möchte aber auch hier nichts aktualisieren.

Ich bin nicht sicher, ob durch (nicht vorhandenen) zu schaffen, die tatsächlich die Aktualisierung jeder spricht, es ist alles so confuzzling :(

Antwort

144

Beginnend mit MongoDB 2.4, es ist nicht mehr notwendig, auf einen eindeutigen Index verlassen (oder jede andere Abhilfe) für die Atom findOrCreate wie Operationen.

Dies ist dank the $setOnInsert operator neu zu 2.4, mit denen Sie Updates angeben können, die nur beim Einfügen von Dokumenten passieren sollte.

Dies, kombiniert mit der upsert Option, bedeutet, dass Sie findAndModify verwenden können, um eine atomare findOrCreate-ähnliche Operation zu erreichen.

db.collection.findAndModify({ 
    query: { _id: "some potentially existing id" }, 
    update: { 
    $setOnInsert: { foo: "bar" } 
    }, 
    new: true, // return new doc if one is upserted 
    upsert: true // insert the document if it does not exist 
}) 

Als $setOnInsert nur wird eingefügt Dokumente betrifft, wenn ein vorhandenes Dokument gefunden wird, wird keine Änderung auftreten. Wenn kein Dokument vorhanden ist, wird ein Objekt mit der angegebenen _id-Eigenschaft eingefügt, und dann wird nur das Insert-Set ausgeführt. In beiden Fällen wird das Dokument zurückgegeben.

+0

Ihr Code wird in mongodb Shell verwendet, aber wie man es in node.js Code verwendet? – Gank

+0

Mein Code kann keine neue Datenbank in node.js einfügen. – Gank

+2

@Gank, wenn Sie den mongodb nativen Treiber für Knoten verwenden, wäre die Syntax mehr wie 'Sammlung.findAndModify ({_ id: 'theId'}, , {$ setOnInsert: {foo: 'bar'}}, {neu: true, upsert: true}, Callback) '. Siehe [die Dokumente] (http://mongodb.github.io/node-mongodb-native/api-generated/collection.html) – numbers1311407

5

Es ist ein bisschen schmutzig, aber man kann es einfach einfügen.

Achten Sie darauf, dass der Schlüssel einen eindeutigen Index auf sie (wenn Sie die _id es ist in Ordnung zu verwenden, es ist schon einzigartig).

auf diese Weise, wenn das Element bereits vorhanden ist, wird eine Ausnahme wird zurückkehren, die Sie fangen können.

Wenn es nicht vorhanden ist, d Okument wird eingefügt.

Aktualisiert: eine detaillierte Erklärung dieser Technik auf der MongoDB Documentation

+0

ok, das ist eine gute Idee, aber für den vorbestehenden Wert wird es einen Fehler aber NICHT den Wert selbst zurückgeben, richtig? – Discipol

+3

Dies ist eigentlich eine der empfohlenen Lösungen für isolierte Sequenzen von Operationen (finden Sie dann erstellen, wenn nicht gefunden, vermutlich) http://docs.mongodb.org/manual/tutorial/isolate-sequence-of-operations/ – numbers1311407

+0

@Discipol if Wenn Sie eine Reihe atomarer Operationen ausführen möchten, sollten Sie das Dokument zunächst sperren, dann ändern und am Ende freigeben. Dies erfordert mehr Abfragen, aber Sie können für den besten Fall optimieren und die meisten Male nur 1-2 Abfragen ausführen. siehe: http://docs.mongodb.org/manual/tutorial/perform-two-phase-commits/ – Madarco

0

Hier ist, was ich getan habe (Ruby-MongoDB-Treiber):

Es wird aktualisiert, wenn es vorhanden ist, und es einsetzen, wenn es nicht der Fall ist.

Verwandte Themen