node_redis : using client.multi within forEach

I have the following code that should retrive the list of devices and get the status and label for each of them:

app.get('/test', function(req, res){
  db.smembers("devices", function(err1, devices){
    var jsonObj = {};
    if(!err1) {
       var i = 0;
       devices.forEach(function(id){
          db.multi([
             ["get", id + ":label"],
             ["get", id + ":status"],
          ]).exec(function (err, replies) {
             jsonObj[id] = {"label":replies[0], "status":replies[1]};
             console.log(jsonObj);     // stuff is added on each loop
          });

          i = i + 1;
          if(i == devices.length){  
             console.log(jsonObj);     // jsonObj is {}     
             h.respond(res, jsonObj);
          }
       });
    } else {
       h.respond(res, { "error" : err1 });
    }
  });
});

devices is a list of ids. For each id, there are 2 keys: "ID:status", "ID:label"

h.respond is an helper method that sends the http response.

I can see the new data being added to the jsonObj on each loop, but when all the loop are done, it's empty.

The code is running asynchronously and is counting up to devices.length before any of the Redis calls actually completes (it doesn't wait for the callbacks from multi to return before continuing). Moving your check into the callback will prevent this.

app.get('/test', function(req, res){
  db.smembers("devices", function(err1, devices){
    var jsonObj = {};
    if(!err1) {
       var i = 0;
       devices.forEach(function(id){
          db.multi([
             ["get", id + ":label"],
             ["get", id + ":status"],
          ]).exec(function (err, replies) {
             jsonObj[id] = {"label":replies[0], "status":replies[1]};
             console.log(jsonObj);     // stuff is added on each loop
             i = i + 1;
             if(i == devices.length){  
                console.log(jsonObj);     // jsonObj is {}     
                h.respond(res, jsonObj);
             }
          });


       });
    } else {
       h.respond(res, { "error" : err1 });
    }
  });
});

Probably make more sense to move this code into a separate function, but hopefully you get the idea. An async library like async provides helper methods that make it much easier to do parallel async loops like this.