0

Using Node.js monk and MongoDB, I want to mimic a table join:

  1. Do a find on collection A
  2. For each result X, do a find in collection B, and update X
  3. Return updated list of results

The asynchronous nature of database commands in monk is giving me trouble. This is my initial code. It doesn't work because the second call to find returns a promise immediately, and the results in xs are sent in the response before they can be updated.

var db = require('monk')('localhost/mydb');
db.get('collection').find({}, function(e,xs) {
  xs.forEach(function(x){
    coll_b.find({a_id:x._id}, function(e,bs) {
      a['bs'] = bs;
    });
  });
  res.json({'results':as});
});

I feel like I should use promise chaining here, but I cannot figure out how to do it. Any help would be greatly appreciated.

John J. Camilleri
  • 4,171
  • 5
  • 31
  • 41
  • You are using a synchronous loop inside an asynchronous function. They haven't returned a result yet. – Blakes Seven Jul 14 '15 at 07:36
  • possible duplicate of [How to return the response from an asynchronous call?](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call) – Blakes Seven Jul 14 '15 at 07:37
  • That post is relevant but I don't feel it answers my question, and it is not a duplicate because my problem is that I need to perform further async queries, and subsequently update the results, before returning them. – John J. Camilleri Jul 14 '15 at 08:02

1 Answers1

1

I think I solved it in this way, inspired by this answer:

var db = require('monk')('localhost/mydb');

// Initial find
db.get('collection').find({}, function(e,xs) {

  // Get inner finds as a list of functions which return promises
  var tasks = xs.map(function(x){
    return function() {
      return coll_b.find({a_id:x._id}, function(e,bs) {
        a['bs'] = bs;
      });
    }
  });

  // Chain tasks together
  var p = tasks[0](); // start the first one
  for(var i = 1; i < tasks.length; i++) p = p.then(tasks[i]);

  // After all tasks are done, output results
  p.then(function(_x){
    res.json({'results':xs});
  });

});

I still feel like this code could be minimised by using chain(), but at least this works as expected.

Note: I realise that performing a second find for each result is not necessarily efficient, but that's not my concern here.

Community
  • 1
  • 1
John J. Camilleri
  • 4,171
  • 5
  • 31
  • 41