-2

I am trying to loop through an array and for each id, update the model, then push the result in another array

this is my code :

async function getSortedAnimals() {
  var i = 0;
  var sortedAnimals = [];
  ids.forEch(async (id) => {
    i++;
    const animal = await this.animalModel.findOneAndUpdate(
      { _id: id },
      {
        $set: {
          order: i,
        },
      },
    );
    sortedAnimals.push(animal);
  });
  console.log(sortedAnimals);
  return sortedAnimals;
} //function

when I console log, the array is empty, I don't know why ! it's like it does not await for the loop to end.

any suggestions ?

SuleymanSah
  • 17,153
  • 5
  • 33
  • 54
  • 1
    Does this answer your question? [Using async/await with a forEach loop](https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop) – Tobias S. Dec 23 '22 at 17:40
  • Welcome to StackOverflow! On top of the solution mentioned above, do also note that your `forEach` is spelled wrong -- you have `forEch` instead. – LeoDog896 Dec 23 '22 at 17:41
  • You are starting up one async function for each iteration of the loop. When the loop finishes you have N async functions running in the background and an empty array. The only thing that's wrong here is your expectation/understanding of the code. – super Dec 23 '22 at 17:45
  • use normal for loop insted of forEach. forEach is not promise aware. – SuleymanSah Dec 23 '22 at 17:46

3 Answers3

1

The result promises are being ignored in the forEach construct. You can replace it with a for...of as below:

async function getSortedAnimals() {
    const ids = [1,2,3];
    const sortedAnimals = [];
    for (const id of ids) {
        const animal = await findOneAndUpdate(
            {_id: id}
        );
        sortedAnimals.push(animal);
    }
    console.log(sortedAnimals);
}

async function findOneAndUpdate(o) {
    return o._id + 1;
}

getSortedAnimals();
Jagrut Sharma
  • 4,574
  • 3
  • 14
  • 19
1

As all the answers say that forEach ignores Promise(async/await). This is a common situation in Javascript. I'd like to suggest to use Promise.all and Array.map instead of for..of loop.

const findOneAndUpdate = async (id) => {
  return await this.animalModel.findOneAndUpdate(
    { _id: id },
    {
      $set: { order: i },
    }
  )
} 
const getSortedAnimals = async () => {
  const sortedAnimals = ids.map(async id => await findOneAndUpdate(id))
  return await Promise.all(sortedAnimals)
}
Kai
  • 101
  • 3
0

Because you are logging the array before pushing objects to it

Iterations are async but not the global loop, however you can use for await

var sortedAnimals = [];
var i = 0;

for await (const id of ids) {            
    i++;
    const animal = await this.animalModel.findOneAndUpdate(
        { _id: id },
        { 
            $set: {
               order: i,
            },
        );

    i++;
}

console.log(sortedAnimals)
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Ahmed Sbai
  • 10,695
  • 9
  • 19
  • 38