Sie müssen im Wesentlichen eine Menge aller Fields
Arrays in Ihrer Sammlung packen, die Sammlung durchlaufen und für jedes Dokument die Felder Teilmenge iterieren. Für jedes Element Fields
aktualisieren Sie die Sammlung mit der $
positional operator.
zum Beispiel innerhalb der inneren Schleife (da Sie 2 verschachtelte Schleifen haben), das Update für das erste Element Array Fields wäre
db.testmarket.updateOne(
{
"_id" : ObjectId("573c9801056848fef667bfde"),
"Fields.Test1" : "boolean",
"Fields.Test2" : "TestLot",
"Fields.Test3" : "TestLot",
"Fields.Test4" : null,
"Fields.Test5" : true,
"Fields.Test6" : true,
"Fields.Test7" : 1,
"Fields.Test8" : false,
"Fields.Test9" : false,
"Fields.Test10" : false,
"Fields.Test11" : false,
"Fields.Test12" : null
},
{ "$set": { "Fields.$.Test13": "1" } }
);
und das nächste Update in der Iteration wäre:
db.testmarket.updateOne(
{
"_id" : ObjectId("573c9801056848fef667bfde"),
"Fields.Test1" : "String",
"Fields.Test2" : "TestSerial",
"Fields.Test3" : "TestSerial",
"Fields.Test4" : null,
"Fields.Test5" : true,
"Fields.Test6" : true,
"Fields.Test7" : 1,
"Fields.Test8" : false,
"Fields.Test9" : false,
"Fields.Test10" : false,
"Fields.Test11" : false,
"Fields.Test12" : null
},
{ "$set": { "Fields.$.Test13": "1" } }
);
und so weiter.
Dieser Algorithmus kann wie folgt realisiert werden:
db.testmarket.find().snapshot().forEach(function(doc) {
doc.Fields.forEach(function(field) {
var query = {},
obj = { Fields: field };
/* function to convert an object into dot notation */
(function recurse(obj, current) {
for(var key in obj) {
var value = obj[key];
var newKey = (current ? current + "." + key : key); /* joined key with dot */
if(value && typeof value === "object") {
recurse(value, newKey); // it's a nested object, so do it again
} else {
query[newKey] = value; // it's not an object, so set the property
}
}
})(obj);
query["_id"] = doc._id;
/* do the update */
db.testmarket.updateOne(
query,
{ "$set": { "Fields.$.Test13": "1" } }
);
});
});
Wie Sie aus dem oben sehen können, beeinträchtigt werden wird Leistung gebunden, da Sie für Schleife doppelt verschachtelten haben. Die äußere Schleife für die erste Iteration, d. H. Das Iterieren der gesamten Sammlung, führt n-mal aus, wobei n
die Gesamtanzahl der Dokumente in der Sammlung ist.
Für jede Iteration der äußeren Schleife, wird die innere Schleife i
mal ausgeführt, wo i
die Länge des Fields
Array ist, so dass die Gesamtkomplexität kann wie folgt berechnet werden: ein für die zweite Iteration der ersten Iteration plus zwei plus drei für die dritte Iteration und so weiter plus n für die n-te Iteration.
1+2+3+4+5+...+n = (n*(n-1))/2 --> O(n^2)
Doing das Updates in einer verschachtelten Schleife mit O(n^2)
Komplexität für sehr große Sammlungen ist nicht sehr effizient. In dieser Hinsicht können Sie Ihren Code optimieren, indem Sie die Bulk API nutzen, die es Ihnen ermöglicht, die Updates als optimierte Chargen zu senden, dh anstatt jede Aktualisierungsanforderung mit jeder Iteration an den Server zu senden, können Sie die Aktualisierungsoperationen in einer Einzelanfrage, die schneller und effizienter ist. Im Folgenden wird gezeigt, wie Sie die Aktualisierungen mithilfe der Methode bulkWrite()
nutzen können.
Für MongoDB Version 3.0 und unten:
var bulk = db.testmarket.initializeUnOrderedBulkOp(),
counter = 0;
db.testmarket.find().snapshot().forEach(function(doc) {
doc.Fields.forEach(function(field) {
var query = {},
obj = { Fields: field };
/* function to convert an object into dot notation */
(function recurse(obj, current) {
for(var key in obj) {
var value = obj[key];
var newKey = (current ? current + "." + key : key); /* joined key with dot */
if(value && typeof value === "object") {
recurse(value, newKey); // it's a nested object, so do it again
} else {
query[newKey] = value; // it's not an object, so set the property
}
}
})(obj);
query["_id"] = doc._id;
/* load up update operations */
bulk.find(query).updateOne({ "$set": { "Fields.$.Test13": "1" } });
counter++;
/* execute the update operations at once in bulk */
if (counter % 500 === 0) {
bulk.execute();
bulk = db.testmarket.initializeUnOrderedBulkOp();
}
});
});
/* clean up the remaining update operations left in the queue */
if (counter % 500 !== 0)
bulk.execute();
MongoDB 3.2 oder neuer:
var ops = [];
db.testmarket.find().snapshot().forEach(function(doc) {
doc.Fields.forEach(function(field) {
var query = {},
obj = { Fields: field };
/* function to convert an object into dot notation */
(function recurse(obj, current) {
for(var key in obj) {
var value = obj[key];
var newKey = (current ? current + "." + key : key); /* joined key with dot */
if(value && typeof value === "object") {
recurse(value, newKey); // it's a nested object, so do it again
} else {
query[newKey] = value; // it's not an object, so set the property
}
}
})(obj);
query["_id"] = doc._id;
/* load up update operations */
ops.push({
"updateOne": {
"filter": query,
"update": { "$set": { "Fields.$.Test13": "1" } }
}
});
counter++;
});
if (counter % 500 === 0) {
db.testmarket.bulkWrite(ops);
ops = [];
}
});
if (counter % 500 !== 0)
db.testmarket.bulkWrite(ops);
Die Zählvariable oben ist es Ihre Bulk-Updates effektiv zu verwalten, wenn Sie Ihre Sammlung groß. Sie können die Aktualisierungsvorgänge stapelweise durchführen und die Schreibvorgänge in Stapeln von 500 an den Server senden, wodurch Sie eine bessere Leistung erzielen, da Sie nicht jede Anforderung an den Server senden, sondern nur einmal alle 500 Anfragen.
Für Massenoperationen legt MongoDB ein internes Standardlimit von 1000 Operationen pro Stapel fest. Daher ist die Auswahl von 500 Dokumenten in dem Sinne gut, dass Sie etwas Kontrolle über die Stapelgröße haben, statt MongoDB den Standard auferlegen zu lassen Operationen in der Größenordnung von> 1000 Dokumenten.
Was haben Sie ausprobiert? – Yogesh
~ db.testmarket.Fields.update ({}, {$ gesetzt: { "Test13": "1"}}, { Upsert: true, multi: true}) ~ – Sam