代码之家  ›  专栏  ›  技术社区  ›  Saurabh Agrawal

MongoDB在一个查询中更新多行

  •  2
  • Saurabh Agrawal  · 技术社区  · 6 年前

    我收藏了以下文件

    {
       "_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有这个功能吗?

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

    3 回复  |  直到 6 年前
        1
  •  5
  •   Saurabh Agrawal    6 年前

    你可以使用 bulk operation Collection.initializeUnorderedBulkOp

    var bulkOp = yourCollection.initializeUnorderedBulkOp();
    
    bulkOp.find({ _id: 1 }).updateOne({ /* update document */ });
    bulkOp.find({ _id: 2 }).updateOne({ /* update document */ });
    // etc
    
    bulkOp.execute();
    

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

        2
  •  2
  •   Orelsanpls    6 年前

    不能使用单个请求执行所需的更改。


    有少量数据的

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

    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
  •  1
  •   Ashh    6 年前

    更简洁的方式

    要更新的数组

    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 } }
          }
        })
      )
    })