Saurabh Agrawal
Saurabh Agrawal

Reputation: 7739

MongoDB update multiple rows in a single query

I have a collection with the following document

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

I want to update this collection like this using a single query.

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

I can do it using forEach but I have to update thousands of records at once which will time consuming. So does MongoDB have this functionality?

Your help will be highly appreciated.

Upvotes: 3

Views: 2490

Answers (3)

Ashh
Ashh

Reputation: 46441

Even more concise way

Array you want to update with

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

Query to for bulk update

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

Upvotes: 1

kmdreko
kmdreko

Reputation: 59882

You can use a bulk operation in nodejs via Collection.initializeUnorderedBulkOp

var bulkOp = yourCollection.initializeUnorderedBulkOp();

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

bulkOp.execute();

You can build it however you need to and then have the database do it all at once.

Upvotes: 6

Orelsanpls
Orelsanpls

Reputation: 23495

You can't perform the changes you want using a single request.

What you can do is :


Having small amount of data

Launch one request for each change to perform

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

Having a large amount of data

Use cursor to handle the data by packs.

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

Upvotes: 2

Related Questions