Der beste Weg , dies zu tun , ist in der Version 4.2 und höher , die in dem Update - Dokument mit der Aggregation Pipeline ermöglicht und das updateOne
, updateMany
oder update
Sammelverfahren. Beachten Sie, dass Letzteres in den meisten, wenn nicht allen Sprachtreibern veraltet ist.
MongoDB 4.2+
In Version 4.2 wurde auch der $set
Pipeline-Stage-Operator eingeführt, der ein Alias für ist $addFields
. Ich verwende $set
hier , wie es Karten mit dem, was wir zu erreichen versuchen.
db.collection.<update method>(
{},
[
{"$set": {"name": { "$concat": ["$firstName", " ", "$lastName"]}}}
]
)
MongoDB 3.4+
In Version 3.4+ können Sie $addFields
die $out
Aggregationspipeline-Operatoren verwenden.
db.collection.aggregate(
[
{ "$addFields": {
"name": { "$concat": [ "$firstName", " ", "$lastName" ] }
}},
{ "$out": "collection" }
]
)
Beachten Sie, dass dadurch Ihre Sammlung nicht aktualisiert wird, sondern die vorhandene Sammlung ersetzt oder eine neue erstellt wird. Auch für Aktualisierungsvorgänge, die "Typumwandlung" erfordern, benötigen Sie eine clientseitige Verarbeitung. Je nach Vorgang müssen Sie möglicherweise die find()
Methode anstelle der .aggreate()
Methode verwenden.
MongoDB 3.2 und 3.0
Dazu verwenden wir $project
unsere Dokumente und verwenden den $concat
Zeichenfolgenaggregationsoperator, um die verkettete Zeichenfolge zurückzugeben. Von dort aus iterieren Sie dann den Cursor und verwenden den $set
Aktualisierungsoperator, um das neue Feld mithilfe von Massenoperationen zu Ihren Dokumenten hinzuzufügen, um maximale Effizienz zu erzielen.
Aggregationsabfrage:
var cursor = db.collection.aggregate([
{ "$project": {
"name": { "$concat": [ "$firstName", " ", "$lastName" ] }
}}
])
MongoDB 3.2 oder neuer
Aus diesem Grund müssen Sie die bulkWrite
Methode verwenden.
var requests = [];
cursor.forEach(document => {
requests.push( {
'updateOne': {
'filter': { '_id': document._id },
'update': { '$set': { 'name': document.name } }
}
});
if (requests.length === 500) {
//Execute per 500 operations and re-init
db.collection.bulkWrite(requests);
requests = [];
}
});
if(requests.length > 0) {
db.collection.bulkWrite(requests);
}
MongoDB 2.6 und 3.0
Ab dieser Version müssen Sie die jetzt veraltete Bulk
API und die zugehörigen Methoden verwenden .
var bulk = db.collection.initializeUnorderedBulkOp();
var count = 0;
cursor.snapshot().forEach(function(document) {
bulk.find({ '_id': document._id }).updateOne( {
'$set': { 'name': document.name }
});
count++;
if(count%500 === 0) {
// Excecute per 500 operations and re-init
bulk.execute();
bulk = db.collection.initializeUnorderedBulkOp();
}
})
// clean up queues
if(count > 0) {
bulk.execute();
}
MongoDB 2.4
cursor["result"].forEach(function(document) {
db.collection.update(
{ "_id": document._id },
{ "$set": { "name": document.name } }
);
})
Sie sollten durchlaufen. Für Ihren speziellen Fall:
quelle
save()
das Dokument vollständig ersetzt wird. Sollteupdate()
stattdessen verwenden.db.person.update( { _id: elem._id }, { $set: { name: elem.firstname + ' ' + elem.lastname } } );
create_guid
, die nur dann eine eindeutige Guid pro Dokument erzeugt, wenn sieforEach
auf diese Weise iteriert wird (dh einfach durch Verwendungcreate_guid
einerupdate
Anweisung mitmutli=true
bewirkt, dass für alle Dokumente dieselbe Guid generiert wird). Diese Antwort hat bei mir perfekt funktioniert. +1Anscheinend gibt es seit MongoDB 3.4 eine Möglichkeit, dies effizient zu tun, siehe Styvanes Antwort .
Veraltete Antwort unten
Sie können (noch) nicht auf das Dokument selbst in einem Update verweisen. Sie müssen die Dokumente durchlaufen und jedes Dokument mithilfe einer Funktion aktualisieren. Sehen Sie diese Antwort für ein Beispiel, oder diese eine für die serverseitige
eval()
.quelle
update
Operation erwähnt. Diese zugehörige Funktionsanforderung ist ebenfalls noch ungelöst.OPEN
.Bei einer Datenbank mit hoher Aktivität können Probleme auftreten, bei denen sich Ihre Aktualisierungen auf das aktive Ändern von Datensätzen auswirken. Aus diesem Grund empfehle ich die Verwendung von snapshot ().
http://docs.mongodb.org/manual/reference/method/cursor.snapshot/
quelle
snapshot()
:Deprecated in the mongo Shell since v3.2. Starting in v3.2, the $snapshot operator is deprecated in the mongo shell. In the mongo shell, use cursor.snapshot() instead.
linkIn Bezug auf diese Antwort ist die Snapshot-Funktion in Version 3.6 gemäß diesem Update veraltet . Ab Version 3.6 ist es also möglich, den Vorgang folgendermaßen auszuführen:
quelle
Starten
Mongo 4.2
,db.collection.update()
kann eine Aggregationspipeline akzeptieren und schließlich das Aktualisieren / Erstellen eines Felds basierend auf einem anderen Feld ermöglichen:Der erste Teil
{}
ist die Übereinstimmungsabfrage, bei der gefiltert wird, welche Dokumente aktualisiert werden sollen (in unserem Fall alle Dokumente).Der zweite Teil
[{ $set: { name: { ... } }]
ist die Update-Aggregationspipeline (beachten Sie die eckigen Klammern, die die Verwendung einer Aggregationspipeline angeben).$set
ist ein neuer Aggregationsoperator und ein Alias von$addFields
.Vergessen Sie nicht
{ multi: true }
, sonst wird nur das erste übereinstimmende Dokument aktualisiert.quelle
Ich habe die obige Lösung ausprobiert, fand sie jedoch für große Datenmengen ungeeignet. Ich habe dann die Stream-Funktion entdeckt:
quelle
Folgendes haben wir uns ausgedacht, um ein Feld für ~ 150_000 Datensätze in ein anderes zu kopieren. Es dauerte ungefähr 6 Minuten, ist aber immer noch deutlich weniger ressourcenintensiv als das Instanziieren und Iterieren derselben Anzahl von Ruby-Objekten.
quelle
Mit MongoDB - Version 4.2 und höher , ist Updates flexibler , da es die Verwendung von Aggregation Pipeline in seinem ermöglicht
update
,updateOne
undupdateMany
. Sie können Ihre Dokumente jetzt mithilfe der Aggregationsoperatoren transformieren und dann aktualisieren, ohne den$set
Befehl explizit angeben zu müssen (stattdessen verwenden wir$replaceRoot: {newRoot: "$$ROOT"}
).Hier verwenden wir die aggregierte Abfrage, um den Zeitstempel aus dem Feld ObjectID "_id" von MongoDB zu extrahieren und die Dokumente zu aktualisieren (ich bin kein SQL-Experte, aber ich denke, SQL bietet keine automatisch generierte ObjectID mit Zeitstempel, die Sie benötigen automatisch dieses Datum erstellen)
quelle
{ $replaceRoot: { newRoot: "$$ROOT" } }
; es bedeutet, das Dokument selbst zu ersetzen, was sinnlos ist. Wenn Sie ersetzen$addFields
durch den Alias$set
undupdateMany
die für einen der Aliase istupdate
, erhalten Sie auf genau die gleiche Antwort wie diese oben.