It is necessary to send a response after forEach is executed

I am working with NodeJS + Mongoose and I am trying to populate an array of objects and then send it to the client, but I cannot do that, the response is always empty because it is sent before the end of the forEach.

router.get('/', isAuthenticated, function(req, res) {
Order.find({ seller: req.session.passport.user }, function(err, orders) {
    //handle error
      var response = [];
      orders.forEach(function(doc) {
        doc.populate('customer', function(err, order) {
          //handle error
          response.push(order);
        });
      });
      res.json(response);
  });
});

      

Is there a way to send it after the loop completes?

+3


source to share


2 answers


Basically, you can use any asynchronous control flow solution like async or promises (see laggingreflex answer ), but I would recommend that you use Mongoose specialized methods to populate the entire array in a single MongoDB request.

The simplest solution is to use Query#populate

method
to get already completed documents:

Order.find({
  seller: req.session.passport.user
}).populate('customer').exec(function(err, orders) {
  //handle error
  res.json(orders);
});

      



But if for some reason you cannot use this method, you can call Model.populate

method
yourself to populate an array of already loaded documents:

Order.populate(orders, [{
  path: 'customer'
}], function(err, populated) {
  // ...
});

      

+5


source


One solution is to use Promises.

var Promise = require('bluebird');

Promise.promisifyAll(Order);

router.get('/', isAuthenticated, function(req, res) {
    Order.findAsync({ seller: req.session.passport.user })
    .then(function(orders) {
        return Promise.all(orders.map(function(doc){
            return Promise.promisify(doc.populate).bind(doc)('customer');
        }));
    }).then(function(orders){
        // You might also wanna convert them to JSON
        orders = orders.map(function(doc){ return doc.toJSON() });
        res.json(orders);
    }).catch(function(err){
        //handle error
    });
});

      



BlueBird .promisifyAll

creates a …Async

version of all the object's functions, saving you an extra step in setting up the initial promise. So instead Order.find

I used Order.findAsync

in the above example

+3


source







All Articles