Reputation: 363
I guess it should be simple for those who familiar with Node.js and Mongoose. I'm trying to get the final result inside async forEach and mongoose find, I can see the results fine in the middle of the function, but when Im trying to get it after the second forEach, I cant.
I have tried to catch the last iteration and bring the results back, but because its async, the last iteration arrived before the find in the middle of the function.
Any suggestions? Here is what I have:
function addUsersInfoForEachVote(req, res, next){
var itemsProcessed = 0;
Questions.findOne({_id: req.body.question}, {answers: 1}).exec(function (err, question) {
var finalVotes = [];
if (err | !question) {
return res.send({
errors: err | "No Question Found"
});
} else {
question.answers.forEach((answer, index, array) => {
var votedUsers = [];
votedUsers = votedUsers.concat(answer.get("votes"));
answer._doc.votes = answer.get("votes").length;
var ansId = answer.answerId;
var aData = {answer: answer, users: {}};
AnswersVote.find({'_id': {$in: getUniqueIds(votedUsers)}},{user: 1})
.populate('user', 'name gender')
.exec(function(err, votesUsers){
if (!err) {
votesUsers.forEach(function(vote){
var user = vote.get("user");
if (user){
aData.users[user.get("id")] = user;
}
});
console.log("ADATA:"+JSON.stringify(aData)); //Here I can see it well! (the second time contain it all)
}
});
//currAns = votedUsers;
itemsProcessed++;
if( itemsProcessed === array.length) {
//HERE I NEED THE FINAL RESULTS:
console.log("ADATA after:"+JSON.stringify(aData));
next();
}
});
}
});
}
Upvotes: 0
Views: 2144
Reputation: 363
First, Thank you all for your help, I'm personally trying to avoid using external libraries if its unnecessary, and because I can check the amount of answers before, here is the right answer:
function addUsersInfoForEachVote(req, res, next){
Questions.findOne({_id: req.body.question}, {answers: 1}).exec(function (err, question) {
var finalVotes = [];
if (err || !question) {
return res.send({
errors: err || "No Question Found"
});
} else {
var ansNum=0; //FOR MY ITERATIONS
var fAns = {full : {}}; //FOR MY FINAL ANSWER
//Here, I can assume we have only two answers so:
question.answers.forEach(function (answer) {
var votedUsers = [];
votedUsers = votedUsers.concat(answer.get("votes"));
answer._doc.votes = answer.get("votes").length;
//answer._doc.answer = votedUsers;
var ansId = answer.answerId;
var aData = {answer: answer, users: {}};
AnswersVote.find({'_id': {$in: getUniqueIds(votedUsers)}},{user: 1}).populate('user', 'name gender').exec(function(err, votesUsers){
if (!err) {
votesUsers.forEach(function(vote){
var user = vote.get("user");
if(user){
aData.users[user.get("id")] = user;
}
});
}
fAns.full[ansId] = aData;
if(ansNum > 0){ //The number of the answers here is "2", but this value can be changed
console.log("FINAL:"+JSON.stringify(fAns)); //Here I have the full response now :)
res.jsonp(fAns);
}
ansNum++;
});
});
}
});
}
Thanks again anyway.
Upvotes: 0
Reputation: 116
You can use async eachLimit or each here Read doc(http://caolan.github.io/async/docs.html#.eachLimit)
async.eachLimit((question.answers || []), 4, function(answer, callback) {
var votedUsers = [];
votedUsers = votedUsers.concat(answer.get("votes"));
answer._doc.votes = answer.get("votes").length;
var ansId = answer.answerId;
var aData = {
answer: answer,
users: {}
};
AnswersVote.find({
'_id': {
$in: getUniqueIds(votedUsers)
}
}, {
user: 1
})
.populate('user', 'name gender')
.exec(function(err, votesUsers) {
if (!err) {
votesUsers.forEach(function(vote) {
var user = vote.get("user");
if (user) {
aData.users[user.get("id")] = user;
}
});
console.log("ADATA:" + JSON.stringify(aData));
}
callback(err);
});
},
function(error) {
next();
}
});
Upvotes: 1
Reputation: 2766
May be you can use async.waterfall
to achieve the desired result.
Refer doc for more information.
Try something like below code:-
function addUsersInfoForEachVote(req, res, next){
var itemsProcessed = 0;
Questions.findOne({_id: req.body.question}, {answers: 1}).exec(function (err, question) {
var finalVotes = [];
if (err | !question) {
return res.send({
errors: err | "No Question Found"
});
} else {
question.answers.forEach((answer, index, array) => {
var votedUsers = [];
votedUsers = votedUsers.concat(answer.get("votes"));
answer._doc.votes = answer.get("votes").length;
var ansId = answer.answerId;
var aData = {answer: answer, users: {}};
async.waterfall([
function(callback){
AnswersVote.find({'_id': {$in: getUniqueIds(votedUsers)}},{user: 1}).populate('user', 'name gender').exec(function(err, votesUsers){
if (!err) {
votesUsers.forEach(function(vote){
var user = vote.get("user");
if(user){
aData.users[user.get("id")] = user;
}
});
console.log("ADATA:"+JSON.stringify(aData)); //Here I can see it well! (the second time contain it all)
callback(null);
}
});
},
function(callback){
//currAns = votedUsers;
itemsProcessed++;
if(itemsProcessed === array.length) {
//HERE I NEED THE FINAL RESULTS:
console.log("ADATA after:"+JSON.stringify(aData));
callback(null);
}
else {callback(null);}
}
], function(err){next();})
});
This may help you. Let me know if it works.
Upvotes: 0