【问题标题】:MongoDB update multiple rows in a single queryMongoDB 在单个查询中更新多行
【发布时间】:2018-10-18 01:39:30
【问题描述】:

我有一个包含以下文档的集合

{
   "_id" : 1,
   "item" : "item1",
   "stock" : 184
}
{
   "_id" : 2,
   "item" : "item2",
   "stock" : 330
}
{
   "_id" : 3,
   "item" : "item3",
   "stock" : 140
}

我想像这样使用单个查询来更新这个集合。

{
   "_id" : 1,
   "item" : "item1",
   "stock" : 80
}
{
   "_id" : 2,
   "item" : "item2",
   "stock" : 60
}
{
   "_id" : 3,
   "item" : "item3",
   "stock" : 170
}

我可以使用forEach 来做到这一点,但我必须一次更新数千条记录,这将非常耗时。那么MongoDB有这个功能吗?

我们将非常感谢您的帮助。

【问题讨论】:

  • 每个商品都有一些新的库存值数组,还是以相同的数量增加所有库存值?
  • @marmor 我将更新股票价值数组。对于我所做的那个例子,我并没有以相同的数量增加所有股票价值。顺便说一句,更新了问题:)
  • 我想这就是你要找的东西stackoverflow.com/questions/51882718/…

标签: node.js mongodb


【解决方案1】:

你可以通过Collection.initializeUnorderedBulkOp在nodejs中使用bulk operation

var bulkOp = yourCollection.initializeUnorderedBulkOp();

bulkOp.find({ _id: 1 }).updateOne({ /* update document */ });
bulkOp.find({ _id: 2 }).updateOne({ /* update document */ });
// etc

bulkOp.execute();

您可以根据需要构建它,然后让数据库一次完成所有工作。

【讨论】:

  • 感谢它对我有用。删除了 await,因为 bulkOp.execute() 不是异步函数。
  • execute(实际上是大多数 mongodb 驱动函数)有两种形式:通过回调参数返回结果,或者,如果没有提供回调,将返回一个承诺(可以等待)
【解决方案2】:

您无法使用单个请求执行您想要的更改。

你可以做的是:


数据量小

为要执行的每个更改启动一个请求

await Promise.all(entries.map(x => model.findOneAndUpdate(...)));

拥有大量数据

使用游标按包处理数据。

const cursor = await model.find({
   _id: {
      $in: idsEntries,
   },
}).cursor().exec();

await handleCursorRead(cursor);

handleCursorRead(cursor) {
   return new Promise((resolve) => {
       cursor.eachAsync((x) => {
           x.stock = ...;

           x.save();
       }, {
          // How many items do we look at same time
          parallel: 250,
       }, () => {
          // When we are done processing all items
          resolve();
       });
   });
}

【讨论】:

    【解决方案3】:

    更简洁的方式

    要更新的数组

    const array = [{
        "_id" : 1,
        "item" : "item1",
        "stock" : 80
    }, {
        "_id" : 2,
        "item" : "item2",
        "stock" : 60
    }, {
        "_id" : 3,
        "item" : "item3",
        "stock" : 170
    }]
    

    批量更新查询

    Model.bulkWrite(
      array.map((data) => 
        ({
          updateOne: {
            filter: { _id: data._id },
            update: { $set: { stock: data.stock } }
          }
        })
      )
    })
    

    【讨论】:

    • 感谢您回答安东尼。我只是想知道这个更快还是initializeUnorderedBulkOp
    • 两者都是批量查询。所以两者都将以类似的方式工作。这只是上述查询的简化方式。
    • 两者都是批量查询。所以两者都将以类似的方式工作。这只是上述查询的简化方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-23
    • 1970-01-01
    • 1970-01-01
    • 2016-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多