我使用Mongoose从MongoDB中提取一些记录,将它们导入另一个系统,然后我想将所有这些文档的状态(文档属性)设置为processed
。
我可以找到这个解决方案:Update multiple documents by id set. Mongoose
我想知道这是否是正确的方法,建立一个由所有文档ID组成的标准,然后执行更新。还请考虑一个事实,即它会有很多文件。
(更新查询的限制是什么?无法在任何地方找到它。官方文档:http://mongoosejs.com/docs/2.7.x/docs/updating-documents.html)
答案 0 :(得分:20)
构建包含所有文档ID的标准然后执行更新的方法必然会引发潜在问题。当您迭代发送每个文档的更新操作的文档列表时,在Mongoose中,您冒着炸毁服务器的风险,特别是在处理大型数据集时,因为您没有等待异步调用完成,然后再转到下一个迭代。你将基本上建立一个"堆栈"未解决的操作直到导致问题 - Stackoverflow。
例如,假设您有一组文档ID,您希望在状态字段上更新匹配的文档:
var processedIds = [
"57a0a96bd1c6ef24376477cd",
"57a052242acf5a06d4996537",
"57a052242acf5a06d4996538"
];
然后对于非常小的数据集,您可以使用数组上的 forEach()
方法迭代它并更新您的集合:
processedIds.forEach(function(id)){
Model.update({"_id": id}, {"$set": {"status": "processed" }}, callback);
});
以上内容适用于小型数据集。但是,当您面对要更新的数千或数百万个文档时,这将成为一个问题,因为您将在循环内重复调用异步代码的服务器。
另一种方法是使用像async的 eachLimit
这样的东西,并迭代数组,为每个项目执行MongoDB更新操作,而从不执行超过x个并行更新同一时间。
最好的方法是使用批量API,这对于批量处理更新非常有效。性能与在多个文档中的每一个上调用更新操作的差异在于,不是每次迭代都向服务器发送更新请求,而是批量API在每1000个请求中发送一次请求(批处理)。
对于支持MongoDB Server >=4.3.0
的Mongoose版本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); }
对于支持MongoDB服务器~3.8.8
的Mongoose版本~3.8.22
,4.x
,>=2.6.x
,您可以按如下方式使用批量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
});
}
答案 1 :(得分:6)
您可以在更新查询中使用 {multi: true}
选项进行批量更新。
示例强>:
employees.update({ _id: { $gt: 3 } },{$inc: { sortOrder: -1 }},{'multi':true});
mongoose 中的上述代码等同于 mongodb 中的以下代码:
db.employees.updateMany({ _id: { $gt: 3 } },{$inc: { sortOrder: -1 }});