tomekfranek
tomekfranek

Reputation: 7099

How to aggregate array of json objects from forEach function?

I want to render array of stories from all projects in node.js. How to do that?

app.get('/stories', function(request, response) {
  var projects_ids = [1,2]; 
  project_ids.forEach(function(id) {
    pivotal.getStories(id, function(err, project_stories) {
      console.log("Stories: " + project_stories);

      return JSON.stringify(project_stories);
    });
  });
  response.send(array_of_stories);
});

In log I get:

Stories: [object Object]
Stories: [object Object]

Upvotes: 1

Views: 1328

Answers (2)

Kyle Weller
Kyle Weller

Reputation: 2623

You want your server to send an array of project_stories objects as a response to the request? I'm not sure where your return statement returns to, so omitting that I would try something similar to the following to send an array of objects as the response to the request. Edit: As pointed out by others, .getStories is asynchronous. Maybe you could try out, caolan's async module. Implemented like this:

var async = require('async');
var array_of_stories = [];

var getStories = function(id, callback) {
  pivotal.getStories(id, function(err, project_stories) {
    array_of_stories.push(project_stories);
  });
}

app.get('/stories', function(request, response) {
  var projects_ids = [1,2];
  async.forEach(project_ids, getStories, function(error) {
    if(!error){
      response.send(array_of_stories);
    }
  });
});

Upvotes: 0

NilsH
NilsH

Reputation: 13821

Your current approach won't work since getStories are async (assumption based on the method signature of getStories). If you can, I would suggest that you create a method on pivotal that can get stories for multiple project ids, so your code would read:

app.get('/stories', function(req, res) {
    var project_ids = [1, 2];
    pivotal.getStories(project_ids, function(err, project_stories) {
        res.send(project_stories);
    }
});

If that is not an option, I would suggest that you look into a flow library like e.g. node-seq. Then you code could read something like this:

app.get('/stories', function(req, res) {
    var project_ids = [1, 2];
    Seq(project_ids)
        .parEach(function(project_id) {
            pivotal.getStories(project_id, this);
        })
        .seq(function() {
            var aggregatedStories = [];
            Hash.map(this.args, (function(arg) {
            // Each parSeq aparently results in an array of objects
                aggregatedStories.push(arg[0]);
            }));
            res.send(aggregatedStories);
        });
});

The Hash.map function is from a node module called hashish

Edit: To elaborate a little more, parEach will execute the functions in parallel, and the following seq would execute after all the callbacks from the parallel executions have finished. node-seq puts the result from each parallel execution into the parameter array of the following seq, hence the somewhat cryptic Hash.map(this.args)

Upvotes: 1

Related Questions