Issue in returning data retrieved from DB queries called in the loop Issue in returning data retrieved from DB queries called in the loop node.js node.js

Issue in returning data retrieved from DB queries called in the loop


Let's start with the general rule for using promises:

Every function that does something asynchronous must return a promise

Which functions are these in your case? It's getPrayerInCat, the forEach callback, and Prayer.find.

Hm, Prayer.find doesn't return a promise, and it's a library function so we cannot modify it. Rule 2 comes into play:

Create an immediate wrapper for every function that doesn't

In our case that's easy with Q's node-interfacing helpers:

var find = Q.nbind(Prayer.find, Prayer);

Now we have only promises around, and do no more need any deferreds. Third rule comes into play:

Everything that does something with an async result goes into a .then callback

…and returns the result. Hell, that result can even be a promise if "something" was asynchronous! With this, we can write the complete callback function:

function getPrayerCount(data2) {    var id = data2.id;    return find({prayerCat:id})//  ^^^^^^ Rule 1    .then(function(prayer) {//  ^^^^^ Rule 3        if (!prayer)            data2.prayersCount = 0;        else            data2.prayersCount = prayer.length;        return data2;//      ^^^^^^ Rule 3b    });}

Now, we have something a bit more complicated: a loop. Repeatedly calling getPrayerCount() will get us multiple promises, whose asynchronous tasks run in parallel and resolve in unknown order. We want to wait for all of them - i.e. get a promise that resolves with all results when each of the tasks has finished.

For such complicated tasks, don't try to come up with your own solution:

Check the API of your library

And there we find Q.all, which does exactly this. Writing getPrayerInCat is a breeze now:

function getPrayerInCat(data) {    var promises = data.map(getPrayerCount); // don't use forEach, we get something back    return Q.all(promises);//  ^^^^^^ Rule 1}

If we needed to do anything with the array that Q.all resolves to, just apply Rule 3.