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

Ond*_*kar 17 mongoose mongodb node.js

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

我可以找到这个解决方案:通过id set更新多个文档.猫鼬

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

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

chr*_*dam 22

构建由所有文档ID组成的标准然后执行更新的方法必然会引起潜在的问题.当您迭代发送每个文档的更新操作的文档列表时,在Mongoose中,您冒着炸毁服务器的风险,特别是在处理大型数据集时,因为您没有等待异步调用完成,然后再转到下一个迭代.您将基本上构建一个未解决的操作的"堆栈",直到这导致问题 - Stackoverflow.

例如,假设您有一组文档ID,您希望在状态字段上更新匹配的文档:

var processedIds = [
    "57a0a96bd1c6ef24376477cd",
    "57a052242acf5a06d4996537",
    "57a052242acf5a06d4996538"
];
Run Code Online (Sandbox Code Playgroud)

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

Model.updateMany(
    { "_id": { "$in": processedIds } }, 
    { "$set": { "status": "processed" } }, 
    callback
);
Run Code Online (Sandbox Code Playgroud)

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

另一种方法是使用像async这样的东西forEach()并迭代数组,为每个项目执行MongoDB更新操作,同时从不执行多于x个并行更新.


最好的方法是使用批量API,这对于批量处理更新非常有效.性能与在多个文档中的每个文档上调用更新操作的差异在于,不是每次迭代都向服务器发送更新请求,而是批量API在每1000个请求(批处理)中发送一次请求.

对于eachLimit支持MongoDB Server的Mongoose版本>=4.3.0,您可以使用3.2.x更新.以下示例显示了如何进行此操作:

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

对于猫鼬的版本bulkWrite(),~3.8.8,~3.8.22支持MongoDB的服务器4.x,你可以按如下方式使用批量API

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); }
Run Code Online (Sandbox Code Playgroud)

  • `insertMany()` 是在 Mongoose 4.4 及更高版本中使用 mongodb 驱动程序进行批量写入的新方法,而`bulkWrite()` 将在未来的某个时候得到支持 [#3998](https://github.com/Automattic /猫鼬/问题/3998)。基本上,`insertMany` 在底层使用了`Model.collection.insertMany()`。我可以指出的主要区别是 `bulkWrite()` 方法提供了执行批量插入、更新和删除操作的能力,而 `insertMany()` 只支持批量插入操作。[文档参考](https://docs.mongodb.com/manual/core/bulk-write-operations/)。 (2认同)

小智 6

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

范例

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

上面的代码在mongoose中等效于下面的代码在mongodb中

db.employees.updateMany({ _id: { $gt: 3 } },{$inc: { sortOrder: -1 }});
Run Code Online (Sandbox Code Playgroud)