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()