Hirak Chhatbar
Hirak Chhatbar

Reputation: 3181

Wait for foreach to complete NodeJS

So, I am creating an API in NodeJS. In one API, I have to call for loop within mongoose query.

How do I wait for the forEach to complete before executing res.send()? I have attached my code below.

router.post("/getResult", function (req, res) {
    const lottery_id = req.body.lottery_id;
    const prizeQuery = Prize.find({"lotid": lottery_id});

    let response = [];

    prizeQuery.exec(function (err, prizes) {
        console.log(prizes.length);
        if (err) return res.send({success: 0, data: err});
        else {
            prizes.forEach(prize => {
                let prizeData = {};
                const winnerQuery = Winner.find({"id": prize._id});
                winnerQuery.exec(function (err, winners) {
                    if (err) return res.send({success: 0, data: err});
                    else {
                        prizeData = {
                            prize: prize,
                            winners: winners
                        };
                        response.push(prizeData);
                    }
                });
            });
        }
    });
    return res.send({success:1, data: response});
});

In the code above, return is called before forEach is completed.

Upvotes: 2

Views: 1435

Answers (2)

Zunnurain Badar
Zunnurain Badar

Reputation: 1042

@Rami's answer is correct but addition to that you can also use forof for your code to work. forof works synchronously so there will be no need for promise. like

          for (let prize of prizes){
                let prizeData = {};
                try{
                  const winnerQuery = Winner.find({"id": prize._id});
                  const winners = await winnerQuery.exec()
                  prizeData = {
                              prize: prize,
                              winners: winners
                          };
                  response.push(prizeData);   
                }catch(err){
                 console.error(err)
                }
            }

Upvotes: 0

Rami Jarrar
Rami Jarrar

Reputation: 4643

Because you are running asynchronous code inside the forEach and forEach will not wait until the asynchronous code finish, to do so, you must wrap your async code with a waiting primitive.

Also the code you provided will call send twice in case of failure, because the return inside the forEach will not actually end the enclosing function.

try {
    await Promise.all(prizes.map(async (prize) => {
        const winners = await Winner.find({"id": prize._id});
        response.push({prize, winners});
    }))
    res.send({success:1, data: response});
} catch (err) {
    res.send({success: 0, data: err});
}

Upvotes: 6

Related Questions