2016-08-03 82 views
10

我甩开了MongoDB的一些记录用猫鼬,将它们导入到另一个系统,然后我想所有这些文件processed设置状态(文件属性)正确的做法。什么是更新MongoDB中多条记录使用猫鼬

我能找到这个解决方案:Update multiple documents by id set. Mongoose

我在想,如果这是正确的做法,建立由所有文件ID的标准,然后进行更新。还请考虑到这将是许多文件的事实。

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

回答

12

建立由所有文件ID的标准,则在更新的方法,势必导致潜在的问题。当你重复的文件发送,每个文档的更新操作的列表,猫鼬您运行大型数据集处理上移动到下一个之前,因为你不等待异步调用完成时,尤其是吹你的服务器的风险迭代。你将基本上建立一个未解决的操作“堆栈”,直到这会导致一个问题 - Stackoverflow。

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

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

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

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

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

另一种方法是使用像异步的eachLimit和迭代每个项目执行MongoDB的更新操作时,切勿进行比个并行更新的同时更在阵列上。


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

对于猫鼬版本>=4.3.0支持MongoDB的服务器3.2.x,您可以使用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); } 

对于猫鼬版本~3.8.8~3.8.224.x支持MongoDB的服务器>=2.6.x,可以按如下方式

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

这正是我一直在寻找。非常感谢! –

+0

你介意告诉我'bulkWrite'与'insertMany'有什么不同? –

+0

或者'collection.insert'与'collection.bulkWrite'有什么不同?我似乎无法找到这些东西的任何官方文档:(参考:http://www.unknownerror.org/opensource/Automattic/mongoose/q/stackoverflow/16726330/mongoose-mongodb-batch-insert –

0

使用批量API您可以在批量更新的更新查询中使用{multi: true}选项。

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

猫鼬上面的代码等同于下面的代码在MongoDB的

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