【问题标题】:Mongoose multi update猫鼬多更新
【发布时间】:2016-05-14 13:25:53
【问题描述】:

我想用不同的值更新多个文档。

我的数据库看起来像这样。

[
    {
        "_id": 1,
        "value": 50
    },
    {
        "_id": 2,
        "value": 100
    }
]

此查询返回错误,因为我传递的是数组而不是 $set 中的对象。

    Model.update({_id: {$in: ids}}, {$set: ids.value}, {multi: true};

我希望我的数据库看起来像这样

[
        {
            "_id": 1,
            "value": 4
        },
        {
            "_id": 2,
            "value": 27
        }
    ]

【问题讨论】:

    标签: node.js mongodb express mongoose


    【解决方案1】:

    假设你有一个对象数组,你想在你的集合中更新匹配的 id,比如

    var soldItems = [
            {
                "_id": 1,
                "value": 4
            },
            {
                "_id": 2,
                "value": 27
            }
        ];
    

    那么您可以在数组上使用 forEach() 方法对其进行迭代并更新您的集合:

    soldItems.forEach(function(item)){
        Model.update({"_id": item._id}, {"$set": {"value": item.value }}, callback);
    });
    

    或使用承诺作为

    var updates = [];
    soldItems.forEach(function(item)){
        var updatePromise = Model.update({"_id": item._id}, {"$set": {"value": item.value }});
        updates.push(updatePromise);
    });
    
    Promise.all(updates).then(function(results){
        console.log(results);
    });
    

    或使用 map()

    var updates = soldItems.map(function(item)){
        return Model.update({"_id": item._id}, {"$set": {"value": item.value }});       
    });
    
    Promise.all(updates).then(function(results){
        console.log(results);
    }); 
    

    对于较大的数组,您可以利用批量写入 API 来获得更好的性能。对于支持 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 bulkOps = soldItems.map(function (item) { 
        return { 
            "updateOne": { 
                "filter": { "_id": item._id } ,              
                "update": { "$set": { "value": item.value } } 
            }         
        }    
    });
    
    // Get the underlying collection via the native node.js driver collection object
    Model.collection.bulkWrite(bulkOps, { "ordered": true, w: 1 }, bulkUpdateCallback);
    

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

    var bulk = Model.collection.initializeOrderedBulkOp(),
        counter = 0;
    
    soldItems.forEach(function(item) {
        bulk.find({ "_id": item._id }).updateOne({ 
            "$set": { "value": item.value }
        });
    
        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
        });
    }
    

    【讨论】:

      【解决方案2】:

      首先您的update() 查询不正确..

      请参阅此here 的文档

      Model.update(conditions, update, options, callback);

      假设您当前的数据库模型包含这样的文档(正如您在问题中描述的那样):

      [
          {
              "_id": 1,
              "value": 50
          },
          {
              "_id": 2,
              "value": 100
         }
      ];
      

      并且您在下面的数组中包含要使用当前数据库的文档进行修改的对象(即文档),如下所示:

      idsArray: [
          {
              "_id": 1,
              "value": 4
          },
          {
              "_id": 2,
              "value": 27
          }
      ];
      

      根据我使用 mongodb 和 mongoose 的经验,我认为您不能使用单行查询更新所有文档(这是您正在尝试做的)..(PS 我不知道,所以我不确定到这个..)

      但要使您的代码正常工作,您将执行以下操作:

      想法:循环遍历文档中的每个文档,即 idsArray 并对其调用 update()..

      所以,下面是代码:

      idsArray.forEach(function(obj) {
          Model.update({_id: obj._id}, {$set: {value: obj.value}});
      });
      

      在上面的代码中,我假设您在 db 文档中已经有了 _id 值,因为它们是上面写的(即"_id": 1)。但是如果它们是这样的"_id": ObjectId('1')

      [
        {
          "_id": ObjectId('1'),
          "value": 50
        },
        .....
        .....
      ]
      

      那么您需要在 update() 查询中将 _id 转换为 ObjectId(obj._id)。 所以你会这样做。

      var ObjectId = require('mongodb').ObjectID;
      
      idsArray.forEach(function(obj) {
         Model.update({_id: ObjectId(obj._id)}, {$set: {value: obj.value}});
      });
      

      附:在继续之前确认它(即_id)..

      希望这会有所帮助。

      干杯,

      【讨论】:

      • 我之前尝试过类似的方法,我循环遍历我的值。我的问题是,如果我采用这种方法,我在哪里设置 res.end();因为如果我在 foreach 完成后设置 res.end(),我仍然有一堆回调等待我的 Model.update 完成。
      • 通过回调(我猜) - 尝试创建一个函数function(callback) {callback();} 更新数据库中的所有文档并将回调返回到主函数中,您将在其中完成这项工作;就这样试试吧。
      • 一个函数(说它:callbackFunc),它将更新您的所有文档,然后从调用它的位置返回回调(假设:mainFunc),所以这意味着当您的所有文档将被更新(意味着 callbackFunc 完成)然后你会做/打电话res.end()
      【解决方案3】:

      多重更新只能用于将多个文档更新为相同的值或使用相同的update operation 更新所有文档。

      如果要更新为不同的值,则必须使用多个更新语句。

      【讨论】:

        猜你喜欢
        • 2012-03-28
        • 2019-07-26
        • 2020-10-18
        • 1970-01-01
        • 2020-11-13
        • 2019-01-23
        • 2016-05-24
        • 2018-09-08
        • 2017-04-28
        相关资源
        最近更新 更多