0

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

    });
}
2
  • 1
    Thank you both, @chridam right :) Commented Aug 17, 2016 at 8:56
  • Second, change if (err | !question) to just if (err) (if you want to use that anyway, the correct syntax is if (err || !question) Commented Aug 17, 2016 at 8:56

3 Answers 3

1

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();
    }
});
Sign up to request clarification or add additional context in comments.

Comments

0

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.

4 Comments

Thank you!, I just copied, and I have "async is not defined", Ill try to debug it anyway..
You need to require the module first: var async = require('async'); and make sure you do npm install async --save
Thanks @chridam Ill try it (although, I think we went too far with it, I think its something with my design)...
Make sure you went through the doc before using the code, so that it will be clearer for you.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.