使用Mongoose更新MongoDB中的许多logging的正确方法是什么?

我使用Mongoose从MongoDB中取出一些logging,将它们导入到另一个系统中,然后我想为所有这些文档设置状态(文档属性)来processed

我可以find这个解决scheme: 通过ID集更新多个文档。 mongoose

我想知道如果这是正确的方法,build立一个由所有文档ID组成的标准,然后执行更新。 还请考虑到这将是许多文件的事实。

(更新查询的限制是什么?在任何地方都找不到。官方文档: http : //mongoosejs.com/docs/2.7.x/docs/updating-documents.html )

构build由所有文档ID组成的标准,然后执行更新的方法势必会导致潜在的问题。 当你迭代每个文档的发送更新操作的文档列表时,在Mongoose中,特别是在处理大型数据集时,会冒着炸毁服务器的风险,因为在转移到下一个之前不等待asynchronous调用完成迭代。 你将基本上build立一个未解决的操作“堆栈”,直到这会导致一个问题 – Stackoverflow。

举个例子,假设你有一个文件id的数组,你想更新状态字段上的匹配文档:

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

那么对于非常小的数据集,您可以使用数组上的forEach()方法迭代它并更新您的集合:

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

以上对于小数据集是可以的。 但是,当您面对数千或数百万个文档更新时,这将成为一个问题,因为您将在循环内重复执行asynchronous代码的服务器调用。

另一种方法是使用诸如async的eachLimit类的eachLimit ,并对每个项目执行MongoDB更新操作的数组进行迭代,而同时从不超过x个并行更新。


最好的方法是使用批量API来处理批量更新。 性能与调用更新操作在许多文档中的每一个上的区别在于,不是每次迭代都向服务器发送更新请求,而是每隔1000个请求(批量)发送请求一次。

对于支持MongoDB Server 3.2.x Mongoose版本>=4.3.0 ,可以使用bulkWrite()进行更新。 以下示例显示了如何解决这个问题:

 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); } 

对于支持MongoDB Server >=2.6.x Mongoose版本~3.8.22~3.8.22 ,可以使用Bulk API如下

 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 }); }