skip to Main Content

I want to do bulk update on mongodb with the following code.

async function main() {
  try {
    const operations:any = []
    users.forEach(async user => {
      const custId = decrypt(user.id)
      const customer = await CustomerModel.findOne({ custId: custId })
      if (customer) {
        let { setting, ...objData } = customer
        setting = {
          ...setting,
          ...{
            description: user.description
          }
        }
        const doc = {
            updateOne: {
              filter: { custId: custId },
              update: { location: 'USA', ...setting }
            }
        }
          operations.push(doc)
      }
    })
    console.log(operations)
    const res = await CustomerModel.bulkWrite(operations)
  } catch (error) {
    console.error(error)
  }
}
main()

When I execute the code above, no document is updated. I think it’s because operations.push section was called after ‘CustomerModel.bulkWrite’ is executed. When I print some debugging lines, i noticed that ‘operations.push’ was called after ‘CustomerModel.bulkWrite(operations)’ line.

Is there any way to fix it?

2

Answers


  1. Please use a for of loop to execute the code sequentially:

    async function main() {
      try {
        const operations: any = [];
        for (const user of users) {
          const custId = decrypt(user.id);
          const customer = await CustomerModel.findOne({ custId: custId });
          if (customer) {
            let { setting, ...objData } = customer;
            setting = {
              ...setting,
              ...{
                description: user.description,
              },
            };
            const doc = {
              updateOne: {
                filter: { custId: custId },
                update: { location: 'USA', ...setting },
              },
            };
            operations.push(doc);
          }
        }
        console.log(operations);
        const res = await CustomerModel.bulkWrite(operations);
      } catch (error) {
        console.error(error);
      }
    }
    main();
    
    Login or Signup to reply.
  2. i noticed that ‘operations.push’ was called after ‘CustomerModel.bulkWrite(operations)’ line.

    This sounds like a classic async issue indeed. In that case, you are troubled by the .forEach() method, which cannot await. Instead, you could use an old school for...of loop, or .map() your Promises and await all of them:

    // Old school for...of loop,
    // makes waiting at each step easy
    for (const user of users) {
      // ...
      const customer = await CustomerModel.findOne({ custId: custId })
      // ...
      operations.push(doc);
    }
    
    // Await all Promises,
    // more parallelism while still waiting for
    // all to complete before moving on
    await Promise.all(
      users.map(async user => {
        // ...
      })
    );
    
    // Variant where you explicitly build
    // your `operations` array from the Promises
    const operations = await Promise.all(
      users.map(async user => {
        // ...
        return doc;
      })
    );
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search