Tilgangen med at opbygge et kriterium bestående af alle dokument-id'er og derefter udføre opdateringen vil helt sikkert forårsage potentielle problemer. Når du gentager en liste over dokumenter, der sender en opdateringsoperation med hvert dokument, risikerer du i Mongoose at sprænge din server, især når du har at gøre med et stort datasæt, fordi du ikke venter på, at et asynkront opkald afsluttes, før du går videre til det næste iteration. Du vil i det væsentlige bygge en "stak" af uløste operationer, indtil dette forårsager et problem - Stackoverflow.
Antag for eksempel, at du havde en række dokument-id'er, som du ønskede at opdatere det matchende dokument i statusfeltet:
const processedIds = [
"57a0a96bd1c6ef24376477cd",
"57a052242acf5a06d4996537",
"57a052242acf5a06d4996538"
];
hvor du kan bruge updateMany()
metode
Model.updateMany(
{ _id: { $in: processedIds } },
{ $set: { status: "processed" } },
callback
);
eller alternativt til virkelig små datasæt kan du bruge forEach()
metode på arrayet for at gentage det og opdatere din samling:
processedIds.forEach(function(id)){
Model.update({ _id: id}, { $set: { status: "processed" } }, callback);
});
Ovenstående er okay for små datasæt. Dette bliver dog et problem, når du står over for tusinder eller millioner af dokumenter, der skal opdateres, da du vil foretage gentagne serverkald med asynkron kode i løkken.
For at overvinde dette, brug noget som async's eachLimit
og iterer over arrayet og udfører en MongoDB-opdateringsoperation for hvert element, mens du aldrig udfører mere end x parallelle opdateringer på samme tid.
Den bedste tilgang ville være at bruge bulk API til dette, som er ekstremt effektiv til at behandle opdateringer i bulk. Forskellen i ydeevne i forhold til at kalde opdateringsoperationen på hvert eneste af de mange dokumenter er, at i stedet for at sende opdateringsanmodningerne til serveren med hver iteration, sender bulk API anmodningerne én gang for hver 1000 anmodninger (batchet).
For Mongoose-versioner >=4.3.0
som understøtter MongoDB Server 3.2.x
, kan du bruge bulkWrite()
for opdateringer. Følgende eksempel viser, hvordan du kan gøre dette:
const bulkUpdateCallback = function(err, r){
console.log(r.matchedCount);
console.log(r.modifiedCount);
}
// Initialize the bulk operations array
const 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 Node.js driver collection object
Model.collection.bulkWrite(bulkUpdateOps, { ordered: true, w: 1 }, bulkUpdateCallback);
bulkUpdateOps = []; // re-initialize
}
})
// Flush any remaining bulk ops
if (counter % 500 != 0) {
Model.collection.bulkWrite(bulkOps, { ordered: true, w: 1 }, bulkUpdateCallback);
}
For Mongoose-versioner ~3.8.8
, ~3.8.22
, 4.x
som understøtter MongoDB Server >=2.6.x
, kan du bruge Bulk API som følger
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
});
}