Search code examples
javascriptasynchronouses6-promise

Return array after forEach loop (async) is finished


I've been struggling with this for a few hours now. I am trying to collect data from my database and push it to an array. When the loop is finished I want to return the array with the retrieved data. Now I managed to make an async forEach loop, but (as expected) I am receiving an empty array, because it doesn't wait for the function to end.

Here's my code:

StatusHandler.prototype.recover = async function recover(modelIds) {
  try {
    const items = [];
    modelIds.forEach(async (id) => {
      try {
        const query = {
          [this.modelId]: ObjectId(id),
          deleted: 'Y',
          xms_status: {
            $nin: [/inactive/, /maintenance/],
          },
        };
        const model = await this.Model.findOne(query);
        console.log(model); // Shows the correct data.
        items.push(model);
      } catch (err) {
        throw err;
      }
    }, this);
    return items; // Returns empty array
  } catch (err) {
    throw err;
  }
};

I saw some related questions and noticed I can use the for..of loop, but I can't use that because of thee Airbnb JavaScript Style Guide (it recommends forEach instead of for..of).

Thanks in advance!


Solution

  • I don't understand why you loop over an array of IDs and use findOne to retrieve your objects, you could use something like this :

    await this.Model.find({_id: {$in: modelIds}});
    

    Also, instead of using forEach to push in an array, why don't you use map ?

    I think you could do something like that :

    async function recover(modelIds) {
      return modelsIds.map(async (modelId, i) => {
        const query = "..."; // your query with the id
        return await this.Model.findOne(query);
      })
    }
    

    And the surround your function call with try/catch to catch errors trhown during your function execution.