【问题标题】:Updating multiple documents using array of object使用对象数组更新多个文档
【发布时间】:2017-07-25 19:51:20
【问题描述】:

我正在使用 express.js 服务器。我正在尝试使用对象数组更新 mongodb 集合中的现有文档使用 mongoose(每个对象都有 _id 属性,其值对应于每个文档 _id。)

一种方法是遍历数组并执行findByIdAndUpdate()

for(var i=0; i < expenseListToEdit.length; i++) {    
    var expense = expenseListToEdit[i];

    Expense.findByIdAndUpdate(expense._id, expense, function(err, model) {
        if (err) {    
            console.log('Error occurred while editing expense');
        }

        console.log('model: ' + util.inspect(model));
    });
}

但是这样我将不得不处理异步场景,并且必须检查所有迭代的数据库查询何时完成,然后只将响应从服务器发送回客户端。

mongoose 中是否有其他方法可以一次性编辑/修改对象数组,然后调用回调?

注意*- 每个数组对象都有 _id 存在,它与文档 _id 值匹配。

【问题讨论】:

    标签: node.js mongodb express mongoose


    【解决方案1】:

    是的,这很有可能。您可以利用批量写入 API 来处理异步操作,从而获得更好的性能,尤其是处理大型数据集。对于支持 MongoDB Server 3.2.x 的 Mongoose 版本 &gt;=4.3.0, 您可以使用 bulkWrite() 进行更新。以下示例显示了您可以如何进行此操作:

    var bulkUpdateCallback = function(err, r){
        console.log(r.matchedCount);
        console.log(r.modifiedCount);
    }
    // Initialise the bulk operations array
    var bulkOps = expenseListToEdit.map(function (expense) { 
        return { 
            "updateOne": { 
                "filter": { "_id": expense._id } ,              
                "update": { "$set": expense } 
            }         
        }    
    });
    
    // Get the underlying collection via the native node.js driver collection object
    Expense.collection.bulkWrite(bulkOps, { "ordered": true, w: 1 }, bulkUpdateCallback);
    

    对于支持 MongoDB Server &gt;=2.6.x 的 Mongoose 版本 ~3.8.8, ~3.8.22, 4.x,您可以使用 Bulk API 如下

    var bulk = Expense.collection.initializeOrderedBulkOp(),
        counter = 0;
    
    expenseListToEdit.forEach(function(expense) {
        bulk.find({ "_id": expense._id })
            .updateOne({ "$set": expense });
    
        counter++;
        if (counter % 500 == 0) {
            bulk.execute(function(err, r) {
               // do something with the result
               bulk = Expense.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
        });
    }
    

    【讨论】:

      【解决方案2】:

      解决办法是将for语句改成async.eachhttp://caolan.github.io/async/docs.html#each:

      警告:每个并行启动所有元素。

      async.each(expenseListToEdit, function (expense, done) {
          Expense.findByIdAndUpdate(expense._id, expense, function(err, model) {
              if (err) {    
                 console.log('Error occurred while editing expense');
                 done(err); // if an error occured, all each is stoped
                 return;
              }
      
              console.log('model: ' + util.inspect(model));
              done();
          });
      }, function (err) {
          // final callback launched after all findByIdAndUpdate calls.
      });
      

      【讨论】:

        【解决方案3】:
        for (let i of expenseListToEdit) {
            Expense.findByIdAndUpdate(i._id, {})
            .exec()
            .then(function updated(expense) {
                if (expense) {
                    //DO SMTH
                }
                }).then(null, function(err) {
                    console.error(err)
                    throw err;
                })
        } 
        

        【讨论】:

        • 请尝试添加一些关于此代码如何工作以及为什么工作的解释,可能带有文档链接
        猜你喜欢
        • 2018-09-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-15
        • 1970-01-01
        • 2022-08-18
        相关资源
        最近更新 更多