Je tire certains enregistrements de MongoDB à l'aide de Mongoose, les importe dans un autre système, puis je voudrais définir le statut (attribut de document) pour tous ces documents sur processed
.
J'ai pu trouver cette solution: Mettre à jour plusieurs documents par ensemble d'ID. Mongoose
Je me demandais si c'était la bonne approche, pour construire un critère composé de tous les identifiants de document, puis effectuer la mise à jour. Veuillez également prendre en compte le fait qu'il va y avoir de nombreux documents.
(Quelle est la limite de la requête de mise à jour? Impossible de la trouver n'importe où. Documentation officielle: http://mongoosejs.com/docs/2.7.x/docs/updating-documents.html )
L'approche consistant à créer un critère composé de tous les identifiants de document, puis à effectuer la mise à jour est susceptible de provoquer des problèmes potentiels. Lorsque vous parcourez une liste de documents envoyant une opération de mise à jour avec chaque document, dans Mongoose, vous courez le risque de faire exploser votre serveur, en particulier lorsque vous traitez un grand ensemble de données, car vous n'attendez pas la fin d'un appel asynchrone avant de passer au suivant itération. Vous allez essentiellement construire une "pile" d'opérations non résolues jusqu'à ce que cela cause un problème - Stackoverflow.
Prenons par exemple, en supposant que vous disposiez d'un tableau d'ID de document que vous vouliez mettre à jour le document correspondant dans le champ d'état:
var processedIds = [
"57a0a96bd1c6ef24376477cd",
"57a052242acf5a06d4996537",
"57a052242acf5a06d4996538"
];
où vous pouvez utiliser la méthode updateMany()
Model.updateMany(
{ "_id": { "$in": processedIds } },
{ "$set": { "status": "processed" } },
callback
);
ou bien pour de très petits ensembles de données, vous pouvez utiliser la méthode forEach()
sur le tableau pour l'itérer et mettez à jour votre collection:
processedIds.forEach(function(id)){
Model.update({"_id": id}, {"$set": {"status": "processed" }}, callback);
});
Ce qui précède est correct pour les petits ensembles de données. Cependant, cela devient un problème lorsque vous êtes confronté à des milliers ou des millions de documents à mettre à jour car vous effectuerez des appels répétés de code asynchrone sur le serveur dans la boucle.
Pour surmonter cela, utilisez quelque chose comme async eachLimit
et parcourez le tableau en effectuant une opération de mise à jour MongoDB pour chaque sans effectuer plus de x mises à jour parallèles en même temps.
La meilleure approche serait d'utiliser l'API en bloc pour cela, ce qui est extrêmement efficace dans le traitement des mises à jour en bloc. La différence de performances par rapport à l'appel de l'opération de mise à jour sur chacun des nombreux documents est qu'au lieu d'envoyer les demandes de mise à jour au serveur à chaque itération, l'API en bloc envoie les demandes une fois toutes les 1000 demandes (par lots).
Pour les versions Mongoose >=4.3.0
Qui prennent en charge le serveur MongoDB 3.2.x
, Vous pouvez utiliser bulkWrite()
pour les mises à jour. L'exemple suivant montre comment procéder:
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); }
Pour les versions Mongoose ~3.8.8
, ~3.8.22
, 4.x
Qui prennent en charge le serveur MongoDB >=2.6.x
, Vous pouvez utiliser l'API Bulk comme suit
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
});
}
Vous pouvez utiliser {multi: true}
dans votre requête de mise à jour pour une mise à jour groupée.
Exemple:
employees.update({ _id: { $gt: 3 } },{$inc: { sortOrder: -1 }},{'multi':true});
Le code ci-dessus en mangouste est équivalent au code ci-dessous en mongodb:
db.employees.updateMany({ _id: { $gt: 3 } },{$inc: { sortOrder: -1 }});