Home > database >  res.json() called before the for loop is fully executed
res.json() called before the for loop is fully executed

Time:10-13

I've got an endpoint in my Application that is supposed to fetch data from a MongoDb Database and return the results to the Client. However, before my for(){} loop finishes execution and an empty array ends up getting sent. How do I change my Code where I can send the Array only when it's completely populated.

Code Below:

app.get("/check/classes/usercart", (req, res) => {

if(req.session.user){

    UserCart.findOne({userId: req.session.user._id}).lean().exec()
    .then((foundUserCart)=>{
        if(foundUserCart){
            console.log("Found user in the UserCart Collection", foundUserCart);

            console.log("Printing User's classCart", foundUserCart.classCart);
            //return res.json({classes: foundUserCart.classCart});

            const classesArray = foundUserCart.classCart;

            let arrayToSend = [];

            for(let i = 0; i < classesArray.length; i  ){
                
                Classes.findById({_id: classesArray[i]}).lean().exec()
                .then((foundClass)=>{
                    console.log("Class Found", foundClass);
                    arrayToSend.push(foundClass);
                    console.log("Printing ArrayToSend", arrayToSend);
                })
                .catch((error)=>{
                    console.log("Error performing findById", error);
                    return res.json({msg: "Server Error"});
                });
            }

            //return arrayToSend;

            //This get's executed before my for loop finishes. I'm new to NodeJs and 
            //the whole asynchronous cycle  
            return res.json({classes: arrayToSend});

        }else{
            return res.json({msg: "No records found for this user"});
        }
        
    })
    .catch((error)=>{
        console.log("Error performing UserCart.find() operation", error);
        return res.json({msg: "Server Error"});
    });

}else{
    return res.redirect("/");
}


});

Please could somebody kindly give me some suggestions? Been stuck on this for a while now. Thanks.

Update: So I got around this by doing the following:

Classes.find({'_id': {$in: classesArray}})
           .then((foundRecords)=>{
               console.log("Found records", foundRecords);
               return res.json({classes: foundRecords}); 
           }).
           catch((error)=>{
            console.log("Error here", error);
 });

This just returns the entire array of records. Probably not the cleanest solution. Could somebody tell me how to do this entire function using Async Await?

CodePudding user response:

Using Promise.all

app.get("/check/classes/usercart", (req, res) => {
    if (req.session.user) {
        return UserCart.findOne({userId: req.session.user._id}).lean().exec()
        .then(foundUserCart => {
            if (foundUserCart) {
                const { classCart } = foundUserCart;
                const arrayToSend = classCart.map(_id => Classes.findById({_id}).lean().exec());
                return Promise.all(arrayToSend)
                    .then(classes => res.json({classes}));
            }
            return res.json({msg: "No records found for this user"});
        })
        .catch((error)=>{
            console.log("Error performing UserCart.find() operation", error);
            return res.json({msg: "Server Error"});
        });
    }
    res.redirect("/");
});

Bonus: Rewrite the above using Async/await

app.get("/check/classes/usercart", async (req, res) => {
    try {
        if (!req.session.user) {
            return res.redirect("/");
        }
        const foundUserCart = await UserCart.findOne({userId: req.session.user._id}).lean().exec();
        
        if (!foundUserCart) {
            return res.json({msg: "No records found for this user"});
        }
        const { classCart } = foundUserCart;
        const arrayToSend = classCart.map(_id => Classes.findById({_id}).lean().exec());
        const classes = await Promise.all(arrayToSend);
        res.json({classes});
    } catch (error) {
        res.json({msg: "Server Error"});
    }
});

CodePudding user response:

You can make your query with multiple IDs in a single operation. That would eliminate the need for the for loop.

const listOfIds = ["46df4667tfs57", "477dfs884v73", "88er58366s"];
Classes.find({ _id: { $in: listOfIds } }).lean().exec()

  • Related