skip to Main Content

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?

3

Answers


  1. 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"});
        }
    });
    
    Login or Signup to reply.
  2. 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"];
    const arrayToSend = await Classes.find({ _id: { $in: listOfIds } }).lean().exec();
    Login or Signup to reply.
  3. Use async/await to clean your code. Your final controller will look like this

    app.get('/check/classes/usercart', async (req, res) => {
      try {
        if (!req.session.user) return res.redirect('/')
    
        const userCart = await UserCart.findOne({ userId: req.session.user._id }).lean()
        if(!userCart) throw new Error('User Not Found!')
    
        const classes = await Classes.find({ _id: { $in: userCart.classCart } }).lean()
    
        return res.json({ classes })
      } catch (error) {
        console.log('Error occured', error)
        res.json({ message: 'Error Occured!', error })
      }
    })
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search