2010-10-25 15 views
91

Ich möchte eine _id MongoDB eines Dokuments aktualisieren. Ich weiß, es ist keine wirklich gute Übung. Aber aus irgendeinem technischen Grund muss ich es aktualisieren. Aber wenn ich versuche, es zu aktualisieren Ich habe:Wie aktualisieren Sie die _id eines MongoDB-Dokuments?

> db.clients.update({'_id':ObjectId("4cc45467c55f4d2d2a000002")}, {'$set':{'_id':ObjectId("4c8a331bda76c559ef000004")}}); 
Mod on _id not allowed 

Und das Update wird nicht gemacht. Wie kann ich es wirklich aktualisieren?

Antwort

152

Sie können es nicht aktualisieren. Sie müssen das Dokument mit einem neuen _id speichern und dann das alte Dokument entfernen.

// store the document in a variable 
doc = db.clients.findOne({_id: ObjectId("4cc45467c55f4d2d2a000002")}) 

// set a new _id on the document 
doc._id = ObjectId("4c8a331bda76c559ef000004") 

// insert the document, using the new _id 
db.clients.insert(doc) 

// remove the document with the old _id 
db.clients.remove({_id: ObjectId("4cc45467c55f4d2d2a000002")}) 
+18

Ein lustiges Problem mit diesem erscheint, wenn ein Feld in diesem Dokument einen eindeutigen Index hat. In diesem Fall schlägt Ihr Beispiel fehl, weil ein Dokument nicht mit einem doppelten Wert in einem eindeutigen indizierten Feld eingefügt werden kann. Sie könnten dies beheben, indem Sie zuerst das Löschen durchführen, aber das ist eine schlechte Idee, denn wenn Ihr Einfügen aus irgendeinem Grund fehlschlägt, sind Ihre Daten jetzt verloren. Sie müssen stattdessen den Index löschen, die Arbeit ausführen und dann den Index wiederherstellen. – skelly

+0

Guter Punkt @skelly! Ich habe zufällig über ähnliche Probleme nachgedacht und deinen frischen Kommentar erst vor 2 Stunden gesehen. Diese Änderung der ID-Problematik wird als ein intrinsisches Problem angesehen, das dadurch verursacht wird, dass der Benutzer die ID wählen kann? – RayLuo

+0

Wenn Sie einen 'doppelten Schlüsselfehler' in der' insert'-Zeile bekommen und sich nicht um das von @skelly erwähnte Problem sorgen, ist die einfachste Lösung, zuerst die 'remove'-Zeile aufzurufen und dann die' insert'-Zeile aufzurufen. Das 'doc' sollte bereits auf Ihrem Bildschirm erscheinen, damit es sich leicht wiederherstellen lässt, im schlimmsten Fall, selbst wenn das Einfügen fehlschlägt, für einfache Dokumente. – philfreo

22

Um es für die ganze Sammlung tun können Sie auch eine Schleife verwenden (basierend auf Niels Beispiel):

db.status.find().forEach(function(doc){ 
    doc._id=doc.UserId; db.status_new.insert(doc); 
}); 
db.status_new.renameCollection("status", true); 

In diesem Fall UserId war die neue ID I

+1

Wäre ein Snapshot() auf find angewiesen worden, das forEach daran zu hindern, neuere Dokumente versehentlich zu übernehmen, wenn es iteriert? –

+0

Dieses Code-Snippet wird nie abgeschlossen. Es wiederholt ständig und wiederholt die Sammlung. Snapshot führt nicht das aus, was Sie erwarten (Sie können es testen, indem Sie einen Snapshot erstellen, indem Sie der Sammlung ein Dokument hinzufügen und dann sehen, dass sich das neue Dokument im Snapshot befindet.) – Patrick

+0

Siehe http://stackoverflow.com/a/28083980/305324 für eine Alternative zum Snapshot.'list()' ist die logische, aber für große Datenbanken kann dies den Speicher erschöpfen – Patrick

0

nutzen wollte im Fall möchten Sie _id in derselben Sammlung (zum Beispiel, wenn Sie einige _ids Präfix wollen) umzubenennen:

db.someCollection.find().snapshot().forEach(function(doc) { 
    if (doc._id.indexOf("2019:") != 0) { 
     print("Processing: " + doc._id); 
     var oldDocId = doc._id; 
     doc._id = "2019:" + doc._id; 
     db.someCollection.insert(doc); 
     db.someCollection.remove({_id: oldDocId}); 
    } 
}); 

if (doc._id.indexOf ("2019:")! = 0) {... erforderlich, um Endlosschleife zu verhindern, da forEach die eingefügten Dokumente auswählt, sogar .snapshot() Methode verwendet.

Verwandte Themen