Daniel
Daniel

Reputation: 145

Multiple Mongoose Calls Within a For Each Loop

I am reading a JSON object and looping through each item. I am first checking to see if the item already exists in the database and if so I want to log a message. If it doesn't already exist I want to add it.

This is working correctly however, I would like to add a callback or finish the process with process.exit();

Because the mongoose calls are asynchronous I can't put it at the end of the for loop because they haven't finished.

Whats the best way I should handle this?

function storeBeer(data) {
    data.forEach((beer) => {
        let beerModel = new Beer({
            beer_id: beer.id,
            name: beer.name,
            image_url: beer.image_url
        });
        Beer.findOne({
            'name': beer.name
        }).then(function (result) {
            if (result) {
                console.log(`Duplicate ${result.name}`)
            } else {
                beerModel.save(function (err, result) {
                    console.log(`Saved: ${result.name}`)
                });
            }
        });
    });
}

Is there anything I should read up on to help solve this?

Upvotes: 2

Views: 402

Answers (1)

jakemingolla
jakemingolla

Reputation: 1639

One means of managing asynchronous resources is through Promise objects, which are first-class objects in Javascript. This means that they can be organized in Arrays and operated on like any other object. So, assuming you want to store these beers in parallel like the question implies, you can do something like the following:

function storeBeer(data) {
    // This creates an array of Promise objects, which can be
    // executed in parallel.
    const promises = data.map((beer) => {
        let beerModel = new Beer({
            beer_id: beer.id,
            name: beer.name,
            image_url: beer.image_url
        });

        return Beer.findOne({
              'name': beer.name
          }).then(function (result) {
              if (result) {
                  console.log(`Duplicate ${result.name}`)
              } else {
                  beerModel.save(function (err, result) {
                      console.log(`Saved: ${result.name}`)
                  });
              }
          });
        );
    });

    return Promise.all(promises);
}

Don't forget that the storeBeer function is now asynchronous, and will need to be utilized either through a Promise chain or through async/await.

For example, to add process exit afterwards:

async function main() {
  const beers = [ ... ];
  await storeBeer(beer);
  process.exit(0);
}

You can also modify the above example to invoke the storeBeer function within a try / catch block to exit with a different error code based on any thrown errors.

Upvotes: 1

Related Questions