1

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!

  • https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop – Evan Trimboli Nov 10 '17 at 10:56
  • But you can make this in a single query to fetch all the models instead of looping & pushing into the array. check if this works `var query = { $in: modelIds, deleted: 'Y', xms_status: { $nin: [/inactive/, /maintenance/], }, };` – keviveks Nov 10 '17 at 10:59
  • this is where a `for` loop would actually behave as you would like ... `for(let i = 0; i < modelIds.length; i++) { let id = modelIds[i]); .... rest of your code ...}` – Jaromanda X Nov 10 '17 at 11:06

1 Answers1

1

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.

boehm_s
  • 5,254
  • 4
  • 30
  • 44
  • Thank you for your answer. I am actually ashamed I haven't thought of that. :') –  Nov 10 '17 at 11:26