0

I am doing a for loop to find the result from mongodb, and concat the array. But I am not getting the final results array when the loop is finished. I am new to node.js, and I think it's not working like objective-c callback.

app.get('/users/self/feed', function(req, res){
    var query = Bill.find({user: req.param('userId')});
    query.sort('-createdAt');
    query.exec(function(err, bill){
        if (bill) {
            var arr = bill;
            Following.findOne({user: req.param('userId')}, function(err, follow){
                if (follow) {
                    var follows = follow.following; //this is a array of user ids
                    for (var i = 0; i < follows.length; i++) {
                        var followId = follows[i];
                        Bill.find({user: followId}, function(err, result){
                            arr = arr.concat(result);
                            // res.send(200, arr);// this is working.
                        });
                    }
                } else {
                    res.send(400, err);
                }
            });
            res.send(200, arr); //if put here, i am not getting the final results
        } else {
            res.send(400, err);
        }
    })
});

2 Answers 2

1

While I'm not entirely familiar with MongoDB, a quick reading of their documentation shows that they provide an asynchronous Node.js interface.

That said, both the findOne and find operations start, but don't necessarily complete by the time you reach res.send(200, arr) meaning arr will still be empty.

Instead, you should send your response back once all asynchronous calls complete meaning you could do something like:

var billsToFind = follows.length;
for (var i = 0; i < follows.length; i++) {
   var followId = follows[i];
   Bill.find({user: followId}, function(err, result){
      arr = arr.concat(result);
      billsToFind -= 1;
      if(billsToFind === 0){
         res.send(200, arr);
      }
   });
}

The approach uses a counter for all of the inner async calls (I'm ignoring the findOne because we're currently inside its callback anyway). As each Bill.find call completes it decrements the counter and once it reaches 0 it means that all callbacks have fired (this works since Bill.find is called for every item in the array follows) and it sends back the response with the full array.

Sign up to request clarification or add additional context in comments.

Comments

0

That's true. Your codes inside for will be executed in parallel at the same time (and with the same value of i I think). If you added console.log inside and after your for loop you will found the outside one will be printed before inside one.

You can wrap the code that inside your for into array of functions and execute them by using async module (https://www.npmjs.org/package/async) in parallel or series, and retrieve the final result from async.parallel or async.series's last parameter.

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.