Quelle est la bonne approche pour mettre à jour de nombreux enregistrements dans MongoDB en utilisant Mongoose

Je extrait certains enregistrements de MongoDB à l’aide de Mongoose, je les importe dans un autre système, puis je souhaite définir le statut (atsortingbut du document) de tous les documents à processed .

Je pourrais trouver cette solution: mettre à jour plusieurs documents par ensemble d’identifiant. Mangouste

Je me demandais si c’était la bonne approche pour créer un critère composé de tous les identifiants de documents, puis effectuer la mise à jour. Veuillez également prendre en compte le fait qu’il y aura beaucoup de documents.

(Quelle est la limite de la requête de mise à jour? Impossible de la trouver nulle part. 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 générer des problèmes potentiels. Lorsque vous parcourez une liste de documents envoyant une opération de mise à jour avec chaque document, vous vous exposez à Mongoose, en particulier lorsque vous manipulez un grand dataset, car vous n’attendez pas la fin d’un appel asynchrone avant de passer au suivant itération. Vous allez essentiellement créer une “stack” d’opérations non résolues jusqu’à ce que cela pose un problème – Stackoverflow.

Par exemple, supposons que vous souhaitiez mettre à jour le document correspondant dans le champ d’état avec un tableau d’identifiants de document:

 var processedIds = [ "57a0a96bd1c6ef24376477cd", "57a052242acf5a06d4996537", "57a052242acf5a06d4996538" ]; 

Ensuite, pour de très petits ensembles de données, vous pouvez utiliser la méthode forEach() sur le tableau pour l’itérer et mettre à jour votre collection:

 processedIds.forEach(function(id)){ Model.update({"_id": id}, {"$set": {"status": "processed" }}, callback); }); 

Ce qui précède convient aux petits ensembles de données. Toutefois, cela devient un problème lorsque vous devez mettre à jour des milliers, voire des millions de documents, car vous allez faire des appels répétés au serveur de code asynchrone au sein de la boucle.

Une alternative serait d’utiliser quelque chose comme eachLimit et d’effectuer une itération sur le tableau en effectuant une opération de mise à jour MongoDB pour chaque élément sans jamais effectuer plus de x mises à jour parallèles en même temps.


La meilleure approche serait d’utiliser l’API en bloc pour cette opération, qui est extrêmement efficace pour traiter les 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 réside dans le fait qu’au lieu d’envoyer les demandes de mise à jour au serveur à chaque itération, l’API en bloc envoie les demandes une fois sur 1 000 (traitement par lots).

Pour les versions de Mongoose >=4.3.0 3.2.x charge MongoDB Server 3.2.x , vous pouvez utiliser bulkWrite() pour les mises à jour. L’exemple suivant montre comment résoudre ce problème:

 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 de Mongoose ~3.8.8 , ~3.8.22 , 4.x qui prennent en charge MongoDB Server >=2.6.x , vous pouvez utiliser l’API en bloc 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 l’option {multi: true} dans votre requête de mise à jour pour la mise à jour en bloc.

Exemple :

 employees.update({ _id: { $gt: 3 } },{$inc: { sortOrder: -1 }},{'multi':true}); 

Le code ci-dessus dans mongoose est équivalent au code ci-dessous dans mongodb :

 db.employees.updateMany({ _id: { $gt: 3 } },{$inc: { sortOrder: -1 }});