0

I have an array of userIDs (MongoDB Objectids)which I want to iterate through and for each one, find its user entry in my MongoDB database of users, and update it, say modify the user's age. Then only when every user has been updated, do I want to say res.send(200); in my Node.js Express app.

I started out with the following code which is just plain wrong because of the asynchronous calls to findById:

for (var i = 0; i < userIDs.length; i++) {
    var userID = userIDs[i];

    User.findById(userID, function (err, user) {
        if (err) throw err;

        // Update user object here

        user.save(function (err, user) {
            if (err) throw err;
            res.send(200);
        });
    });
}

Any ideas how I can do this? Is there perhaps a synchronous version of findById? Or perhaps a way to map through the array and apply a function to each element?

Thanks!

2
  • "just plain wrong because of the asynchronous", are you real? it is intentionally asynchronous not to block Commented Jun 12, 2014 at 17:48
  • @IlanFrumer what I meant is me doing res.send(200) in the asynchronous block is plain wrong when I have multiple objects to update. Of course I know it is intentionally asynchronous not to block. Commented Jun 12, 2014 at 17:53

2 Answers 2

2

I think you want the forEach method of npm's async module. It would look something like this:

async.forEach(userIDs, function(id, callback) {
    User.findById(id, function(err, user){
        if(err) throw err;
        user.save(function(err, user){
            if(err) throw err;
            callback();
        }
    }, function(err){
        if(err){
            throw err;
        } else {
            res.send(200);
        }
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Don't throw in the iterator function. You should instead pass the error to the callback callback(err) (if you want to stop the iteration) or ignore it (if you want to ignore it). You really shouldn't throw in any asynchronous code, actually.
Wow thanks for introducing the async library! It's got some amazing functions in there! This worked!
Duly noted, Aaron Dufour. I've actually been trying to decide the best place for such errors to finally be consumed.
2

The best way is to use promises.

An example with Q#all:

var q = require('Q');

var promises = userIDs.map(function(userID){

  var deferred = q.defer();

  User.findById(userID, function (err, user) {
     if (err) return deferred.reject(err);

    // Update user object here

    user.save(function (err, user) {
      if (err) return deferred.reject(err);      
      deferred.resolve(user);
    });
  });

  return deferred.promise;

});


q.all(promises)
  .then(function(users){
    res.json(users);
  })
  .fail(function(err){
    res.send(500,err);
  });

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.