Der Ansatz, ein Kriterium aller Dokument-IDs aus dem Aufbau und die Aktualisierung durchgeführt worden ist, gebunden an Mögliche Probleme verursachen. Wenn Sie eine Liste von Dokumenten durchlaufen, die mit jedem Dokument eine Aktualisierungsoperation senden, riskieren Sie in Mongoose den Server zu sprengen, besonders wenn Sie mit einem großen Dataset arbeiten, weil Sie nicht auf einen asynchronen Aufruf warten, bevor Sie zum nächsten gehen Iteration. Sie werden im Wesentlichen einen "Stapel" ungelöster Operationen erstellen, bis dies ein Problem verursacht - Stackoverflow.
Nehmen Sie zum Beispiel, angenommen, Sie eine Reihe von Dokumenten-IDs hatte, dass Sie das passende Dokument auf dem Statusfeld aktualisieren wollte:
var processedIds = [
"57a0a96bd1c6ef24376477cd",
"57a052242acf5a06d4996537",
"57a052242acf5a06d4996538"
];
dann für wirklich kleine Datensätze Sie die Methode forEach()
nutzen könnten auf das Array zu iterieren und aktualisieren Sie Ihre Sammlung:
processedIds.forEach(function(id)){
Model.update({"_id": id}, {"$set": {"status": "processed" }}, callback);
});
Das obige ist in Ordnung für kleine Datensätze. Dies wird jedoch zu einem Problem, wenn Sie mit Tausenden oder Millionen von zu aktualisierenden Dokumenten konfrontiert werden, da Sie wiederholte Serveraufrufe von asynchronem Code innerhalb der Schleife ausführen.
Eine Alternative wäre so etwas wie eachLimit
des async zu nutzen und über das Array iterieren für jedes Element eines MongoDB Aktualisierungsvorgang ausführen, während nie mehr als x parallel Updates zur gleichen Zeit durchführen.
Der beste Ansatz wäre, die Bulk-API dafür zu verwenden, die bei der Verarbeitung von Bulk-Aktualisierungen äußerst effizient ist. Der Unterschied in der Leistung im Vergleich zum Aufrufen der Aktualisierungsoperation für jedes der vielen Dokumente besteht darin, dass die Bulk-API die Anforderungen nicht einmal pro 1000 Anforderungen (stapelweise) sendet, sondern die Aktualisierungsanforderungen mit jeder Iteration an den Server sendet.
Für Mongoose Versionen >=4.3.0
die 3.2.x
MongoDB Server unterstützt, können Sie bulkWrite()
für Updates verwenden.Das folgende Beispiel zeigt, wie Sie vorgehen können:
var bulkUpdateCallback = function(err, r){
console.log(r.matchedCount);
console.log(r.modifiedCount);
}
// Initialise the bulk operations array
var bulkUpdateOps = [],
counter = 0;
processedIds.forEach(function(id) {
bulkUpdateOps.push({
"updateOne": {
"filter": { "_id": id },
"update": { "$set": { "status": "processed" } }
}
});
counter++;
if (counter % 500 == 0) {
// Get the underlying collection via the native node.js driver collection object
Model.collection.bulkWrite(bulkOps, { "ordered": true, w: 1 }, bulkUpdateCallback);
bulkUpdateOps = []; // re-initialize
}
})
if (counter % 500 != 0) { Model.collection.bulkWrite(bulkOps, { "ordered": true, w: 1 }, bulkUpdateCallback); }
Für Mongoose Versionen ~3.8.8
, ~3.8.22
, 4.x
die Unterstützung MongoDB Server >=2.6.x
, könnten Sie die Bulk-API verwenden, wie
var bulk = Model.collection.initializeOrderedBulkOp(),
counter = 0;
processedIds.forEach(function(id) {
bulk.find({ "_id": id }).updateOne({
"$set": { "status": "processed" }
});
counter++;
if (counter % 500 == 0) {
bulk.execute(function(err, r) {
// do something with the result
bulk = Model.collection.initializeOrderedBulkOp();
counter = 0;
});
}
});
// Catch any docs in the queue under or over the 500's
if (counter > 0) {
bulk.execute(function(err,result) {
// do something with the result here
});
}
Das ist genau das, was ich suchte. Danke vielmals! –
Würde es Ihnen etwas ausmachen, mir zu sagen, wie sich "bulkWrite" von "insertMany" unterscheidet? –
Oder wie unterscheidet sich 'collection.insert' von' collection.bulkWrite'? Ich kann anscheinend keine offizielle Dokumentation zu diesen Sachen finden :(Referenz: http://www.unknownerror.org/opensource/Automatic/mongoose/q/stackoverflow/16726330/mongoose-mongodb-batch-insert –