NodeJS asynchronous with Q promises - javascript

I'm working with Nodejs and i want to use promises in order to make a full response after a for loop.
exports.getAlerts = function(req,res,next){
var detected_beacons = [];
if (!req.body || Object.keys(req.body).length == 0) {
res.status(401);
res.json({message:'No data sent'});
return
}
var nets = req.body.networks;
db.collection("beaconConfig", function(err, beaconConfigCollection){
if (!err){
var promises = [];
for(var i=0;i<nets.length;i++){
var defer = q.defer();
beaconConfigCollection.find({$or: [{"data.major" : nets[i].toString()},{"data.major" : nets[i]}], batteryLevel : {$lt : 70}}).toArray(function(errFind, saver){
if (!errFind && saver && saver.length > 0){
promises.push(defer.promise);
console.log("--------------------savers -------------------");
console.log(saver);
for(var j=0; j<saver.length;j++){
console.log("--------------------saver[j]-------------------");
console.log(saver[j]);
var detected = {}
var major = saver[j].data.major;
detected.major = major;
console.log("--------------------detected -------------------");
console.log(detected);
detected_beacons.push(detected);
defer.resolve(detected);
}
}
});
}
q.all(promises).then(function(results){
console.log("--------------------detected_beacons -------------------");
console.log(detected_beacons);
res.json(detected_beacons);
});
} else {
console.error(err);
res.status(500);
res.json({message:"Couldn't connect to database"});
}
});};
All the consoles.log works fine unless the last one, the ---detected_beacons--- one, which is THE FIRST ONE to be shown and it is empty.
That is the reason why i'm thinking that the promises are not working well. I have var q = require('q'); at the top and the mongo connection does not return any problem.
Thanks for the help.

First of all, an awesome guide about how to get along with Promises.
Well, haters gonna hate but there is nothing wrong with Promises at all (at least, I hope so).
According to 'MongoDb for Node' documentation, .toArray() returns a Promise, like most of the methods of this library. I felt free to make some appointments along your code:
exports.getAlerts = function(req, res, next) {
if (!req.body || Object.keys(req.body).length == 0) {
res.status(401);
res.json({message: 'No data sent'});
return;
}
// db.collection returns a promise :)
return db.collection("beaconConfig").then(function(beaconConfigCollection) {
// you can use .map() function to put together all promise from .find()
var promises = req.body.networks.map(function(net) {
// .find() also returns a promise. this promise will be concat with all
// promises from each net element.
return beaconConfigCollection.find({
$or: [{
"data.major": net.toString()
}, {
"data.major": net
}],
batteryLevel: {
$lt: 70
}
}).toArray().then(function(saver) {
// you can use the .find() response to create an array
// with only the data that you want.
return saver.map(function(saverElement) {
// your result array will be composed using saverElement.data.major
return saverElement.data.major;
});
}).catch(function(err) {});
});
// use q.all to create a promise that will be resolved when all promises
// from the array `promises` were resolved.
return q.all(promises);
}).then(function(results) {
console.log("results", results);
}).catch(function(err) {});
};
I hope it helps you!

Related

Promises inside loop to wait

I have this code:
var services = ['EC2', 'S3', 'RDS', 'IAM']
var promises = [];
for(var i = 0; i < services.length; i++) {
var promise = awsStatus('us-east-1', services[i])
promises.push(promise);
console.log(promises);
}
q.all(promises).then(function(data){
console.log(promises);
});
it's supposed to loop on the services array with the awsStatus method. The problem is that sometimes I get all the results I want:
{ service: 'IAM', status: 0 }
{ service: 'EC2', status: 0 }
{ service: 'RDS', status: 0 }
But sometimes I get incomplete results. I thought I needed .then after awsStatus but that also didn't resolve this. What else is wrong in this piece of code?
since now there's a comment, I've also tried this :
var services = ['EC2', 'S3', 'RDS', 'IAM']
var promises = [];
for(var i = 0; i < services.length; i++) {
var promise = awsStatus('us-east-1', services[i]).then(function(promise){
promises.push(promise);
//console.log(promises);
});
}
q.all(promises).then(function(data){
console.log(promises);
});
and it produces the same results.
Try using .each
Promise.each(services, function(service) {
return awsStatus('us-east-1', service).then(function(promise){
promises.push(promise);
//console.log(promises);
});
}).then(function() {
console.log('Done with all instances');
});
I can suggest a solution using async library as follows:
var services = ['EC2', 'S3', 'RDS', 'IAM']
async.map(services,
function(item, done){
awsStatus('us-east-1', item).then(
function(){
done(null, "Completed item " + item);
},
function(err){
done(err + " in item " + item, null);
}
);
},
function(err, results){
if(err) return console.log(err);
console.log(results);
}
);
It will fail and stop executing if one of the promises returns an error. If dont want to stop you can return null in the error function of promise instead of error message as the first argument of done method
There are two problems in your code:
Using q.all() does not guarantee that the code will wait for all the promises to resolve. If one of them is rejected, the then method would be called, not waiting for the rest of the promises. You can solve that by using q.allResolved() instead.
You are logging the wrong objects. You should be logging the results of the promises, and not the promise objects themselves.
Example of how to solve both problems:
q.allResolved(promises).then(function(results) {
console.log(results);
}).catch(function(err) {
console.error(err);
});

how to can i handle multiple callbacks return values in nodejs?

I am trying to perform sql queries based on the callback results in if conditions but i am unable to write the code .so please provide som information in code
app.get('/resell-property', function(req, res) {
var data = {}
data.unit_price_id = 1;
function callback(error, result) {
if (result.count == 0) {
return hp_property_sell_request.create(data)
}
else if (result.count > 0) {
return hp_unit_price.findAll({
where: {
unit_price_id: data.unit_price_id,
hp_property_id: data.property_id,
hp_unit_details_id: data.unit_details_id
}
})
}
}
hp_property_sell_request.findAndCountAll({
where: {
unit_price_id: data.unit_price_id
}
}).then(function (result) {
if (result) {
callback(null, result);
}
});
});
In this how can i write the callbacks for
hp_property_sell_request.create(data) ,hp_unit_price.findAll({
where: {
unit_price_id: data.unit_price_id,
hp_property_id: data.property_id,
hp_unit_details_id: data.unit_details_id
}
})
In that after returning result again i have to handle callbacks and perform this query
if(result.request_id){
return hp_unit_price.findAll({
where:{
unit_price_id:result.unit_price_id,
hp_property_id:result.property_id,
hp_unit_details_id:result.unit_details_id
}
}).then(function (result){
if(result.is_resale_unit==0 && result.sold_out==0){
return Sequelize.query('UPDATE hp_unit_price SET resale_unit_status=1 WHERE hp_unit_details_id='+result.unit_details_id+' and hp_property_id='+result.property_id)
}
})
}
The promise resolve function takes only one input argument, so if you need to pass in multiple stuff, you have to enclose them in a single object. Like, if you have to go with something like:
database.openCollection()
.then(function(collection){
var result = collection.query(something);
var resultObject = { result: result, collection: collection };
})
.then(function(resultObject){
doSomethingSyncronousWithResult(resultObject.result);
resultObject.collection.close();
});
You can't use Promise all if all of your stuff isn't a result of a promise resolve, you might need to go with something like this.
Disclaimer: The code example is a very poor one, but it explains the concept.
I would suggest you to learn about Promises, particularly Bluebird.
You can promisify traditional callback methods.
I would also create model level functions in different files. Here's an example.
parent.js
const db = require("./connections/database"); // connection to database
const getChildForParent = function (parentId, childId, callback) {
db.find({parent: parentId, child_id: childId}, "childrenTable", function(err, result) {
if (err) {
return callback(err);
}
return callback(null, result);
});
};
children.js
const db = require("./connections/database"); // connection to database
const getToysForChild = function (childId, callback) {
db.find({toy_belongs_to: parentId}, "toysTable", function(err, result) {
if (err) {
return callback(err);
}
return callback(null, result);
});
};
Then in controller you can do something like this:
const Bluebird = require("bluebird");
const Parent = require("./parent.js");
const Child = require("./child.js");
// Promisifying adds "Async" at the end of your methods' names (these are promisified)
Bluebird.promisifyAll(Parent);
Bluebird.promisifyAll(Child);
// Just an example.
app.get("/parent/:parentId/children/:childId", function(req, res) {
return Bluebird.try(function() {
return User.getChildForParentAsync(req.params.parentId, req.params.childId);
}).then(function(child) {
return Child.getToysForChildAsync(child.child_id);
}).then(function(toys) {
// Do something with toys.
});
});
Of course you can do much more with this and this is not the only way.
Also you can use Promise.all(). This method is useful for when you want to wait for more than one promise to complete.
Let's say you have a list of urls that you want to fetch and process the results after all the data has been fetched.
var urls = [url1, url2, url3, url4, url5 .......... ];
var Bluebird = require("bluebird");
var request = require("request"); // callback version library
Bluebird.promisifyAll(request);
// create a list which will keep all the promises
var promises = [];
urls.forEach(function(url) {
promises.push(request.getAsync(url1));
});
// promises array has all the promises
// Then define what you want to do on completion.
Bluebird.all(promises).then(function(results) {
// results is an array with result a url in an index
// process results.
});
I would recommend to use Promises to solve that. If you need all results of all Requests, when they are all done Promise.all() will do that for you. Your basic could look like that:
var req1 = new Promise(function(res, rej){
var req = new XMLHttpRequest()
…
req.addEventListener('load', function (e) {
res(e);
})
var req2 = //similar to the above
Promise.all([req1, req2, …]).then(function(values){
//all requests are done here and you can do your stuff
});
You can also use the new fetch api, which creates Promises like so:
var req1 = fetch(…);
var req2 = fetch(…);
Promise.all([req1, re2, …]).then(…);

getting object Parse from a loop

In a Parse server function, it's getting Matches and profiles.
From a query to get matches another function is called to get Profiles by id but the result is :
{"_resolved":false,"_rejected":false,"_reso resolvedCallbacks":[],"_rejectedCallbacks":[]}
Main Query :
mainQuery.find().then(function(matches) {
_.each(matches, function(match) {
// Clear the current users profile, no need to return that over the network, and clean the Profile
if(match.get('uid1') === user.id) {
match.set('profile2', _processProfile(match.get('profile2')))
match.unset('profile1')
}
else if (match.get('uid2') === user.id) {
var profileMatch = _getProfile(match.get('profile1').id);
alert(">>>"+JSON.stringify(profileMatch));
match.set('profile1', _processProfile(match.get('profile1')))
match.unset('profile2')
}
})
the function to get Profile info:
function _getProfile(id){
var promise = new Parse.Promise();
Parse.Cloud.useMasterKey();
var queryProfile = new Parse.Query(Profile);
return queryProfile.equalTo("objectId",id).find()
.then(function(result){
if(result){
promise.resolve(result);
alert("!!!!"+result);
}
else {
console.log("Profile ID: " + id + " was not found");
promise.resolve(null);
}
},
function(error){
promise.reject(error)
});
return promise;
}
Just found this a little late. You've probably moved on, but for future readers: the key to solving something like this is to use promises as returns from small, logical asynch (or sometimes asynch, as in your case) operations.
The whole _getProfile function can be restated as:
function _getProfile(id){
Parse.Cloud.useMasterKey();
var queryProfile = new Parse.Query(Profile);
return queryProfile.get(id);
}
Since it returns a promise, though, you cannot call it like this:
var myProfileObject = _getProfile("abc123");
// use result here
Instead, call it like this:
_getProfile("abc123").then(function(myProfileObject) { // use result here });
Knowing that, we need to rework the loop that calls this function. The key idea is that, since the loop sometimes produces promises, we'll need to let those promises resolve at the end.
// return a promise to change all of the passed matches' profile attributes
function updateMatchesProfiles(matches) {
// setup mainQuery
mainQuery.find().then(function(matches) {
var promises = _.map(matches, function(match) {
// Clear the current users profile, no need to return that over the network, and clean the Profile
if(match.get('uid1') === user.id) {
match.set('profile2', _processProfile(match.get('profile2'))); // assuming _processProfile is a synchronous function!!
match.unset('profile1');
return match;
} else if (match.get('uid2') === user.id) {
var profileId = match.get('profile1').id;
return _getProfile(profileId).then(function(profileMatch) {
alert(">>>"+JSON.stringify(profileMatch));
match.set('profile1', _processProfile(match.get('profile1')))
match.unset('profile2');
return match;
});
}
});
// return a promise that is fulfilled when all of the loop promises have been
return Parse.Promise.when(promises);
}

Sequelize wait until loop finished with callback

coming from a php background, I'm trying to get my head around this callback stuff.
Basically I wanna get some rows, then I would like to loop through these rows and check them against an other model (different db). I want the call back to wait until they all have been looped through and checked.
The callback gets called before sequelize has looped through all the results.
Basically I want the function to be 'blocking'. What do I have to change?
toexport.getlasttransactions = function(lower,upper,callback){
var deferred = Q.defer();
var transactionsToUpdate = [];
///////////////////////////
// set import conditions //
///////////////////////////
var lowerbound = (lower) ? lower.format() : moment.utc().subtract(10, 'minutes').format();
var upperbound = (upper) ? upper.format() : moment.utc().format();
///////////////////////////////
// get IDs From Failed syncs //
///////////////////////////////
FailedSync.find({ limit: 100 })
.then(function(res){
var FailedIDs = [];
_.each(res, function(value,index){
FailedIDs.push(value.transaction_id);
});
// build condition
var queryCondition = { where: { updated_at: { between: [lowerbound,upperbound] } }, limit: 3 };
if(FailedIDs.length > 0){
queryCondition = {
where: Sequelize.and({ updated_at: { between: [lowerbound,upperbound] } },
Sequelize.or(
{ id: FailedIDs }
))
}
}
//////////////////////////////
// get Phoenix Transactions //
//////////////////////////////
PhoenixTransaction
.findAll(queryCondition)
.then(function(poenixTrx){
_.each(poenixTrx, function(value, index){
Transaction.findOne({ where: { id: value.id }})
.then(function(result){
if(!result || result.length === 0){
transactionsToUpdate.push(value);
console.log('!result || result.length === 0')
}
else if(result && result.length === 1){
if(result.hash != value.hash){
transactionsToUpdate.push(value);
console.log('result.hash != poenixTrx[i].hash')
}
}
})
.catch(function(err) {
console.log(err)
})
})
deferred.resolve(transactionsToUpdate);
})
.catch(function(err){
throw new Error("Something went wrong getting PhoenixTransaction")
})
})
deferred.promise.nodeify(callback);
return deferred.promise;
}
You have a lot of patterns new promise users have in your code:
You're using a deferred when you don't need to.
You're not using promise aggregation methods
You're not waiting for things in appropriate places but nesting instead.
Promises represent a value over time. You can use promises and access their result via then at a later point and not just right away - Sequelize's promises are based on bluebird and offer a rich API that does aggregation for you.
Here is an annotated version of cleaned up code - note it is not nesting:
toexport.getlasttransactions = function(lower,upper){ // no need for callback
var lowerbound = (lower || moment.utc().subtract(10, 'minutes')).format();
var upperbound = (upper || moment.utc()).format();
// use `map` over a `each` with a push.
var failedIds = FailedSync.find({ limit: 100 }).map(function(value){
return value.transaction_id;
});
// build condition.
var queryCondition = {
where: { updated_at: { between: [lowerbound,upperbound] } }, limit: 3
};
var query = failedIds.then(function(ids){ // use promise as proxy
if(ids.length === 0) return queryCondition;
return { // You can return a value or a promise from `then`
where: Sequelize.and({ updated_at: { between: [lowerbound,upperbound] } },
Sequelize.or({ id: ids});
};
});
var pheonixTransactions = query.then(function(condition){
return PhoenixTransaction.findAll(queryCondition); // filter based on result
});
return pheonixTransactions.map(function(value){ // again, map over each
return Transaction.findOne({ where: { id: value.id }}); // get the relevant one
}).filter(function(result){ // filter over if chain and push
return (!result || result.length === 0) ||
((result && result.length === 1) && result.hash != value.hash);
});
};
Ideally you'll want to either use something like Bluebird's reduce with an array of promises, but I'll provide an async.series implementation as its easier to understand.
Install async
npm install async
Require it in your file
var async = require('async')
Then implement it as such:
//////////////////////////////
// get Phoenix Transactions //
//////////////////////////////
PhoenixTransaction
.findAll(queryCondition)
.then(function(poenixTrx){
var queryArray = poenixTrx.map(function(value){
return function(callback){
Transaction.findOne({ where: { id: value.id }})
.then(function(result){
if(!result || result.length === 0){
transactionsToUpdate.push(value);
console.log('!result || result.length === 0')
}
else if(result && result.length === 1){
if(result.hash != value.hash){
transactionsToUpdate.push(value);
console.log('result.hash != poenixTrx[i].hash')
}
}
// trigger callback with any result you want
callback(null, result)
})
.catch(function(err) {
console.log(err)
// trigger error callback
callback(err)
})
}
})
// async.series will loop through he queryArray, and execute each function one by one until they are all completed or an error is thrown.
// for additional information see https://github.com/caolan/async#seriestasks-callback
async.series(queryArray, function(err, callback){
// after all your queries are done, execution will be here
// resolve the promise with the transactionToUpdate array
deferred.resolve(transactionsToUpdate);
})
})
.catch(function(err){
throw new Error("Something went wrong getting PhoenixTransaction")
})
The whole thing is a little messy to be honest. Especially the promise/callback mix up will probably cause you problems at some point. Anyway you use the deferred.resolve on the transactionsToUpdate which is just an array so it calls the callback right away.
If you keep that script as it is use instead of _.each something like async (https://github.com/caolan/async) to run your transactions in paralell and use that as callback.
It could look like this:
toexport.getlasttransactions = function(lower,upper,callback){
var transactionsToUpdate = [];
///////////////////////////
// set import conditions //
///////////////////////////
var lowerbound = (lower) ? lower.format() : moment.utc().subtract(10, 'minutes').format();
var upperbound = (upper) ? upper.format() : moment.utc().format();
///////////////////////////////
// get IDs From Failed syncs //
///////////////////////////////
FailedSync.find({ limit: 100 })
.then(function(res){
var FailedIDs = [];
_.each(res, function(value,index){
FailedIDs.push(value.transaction_id);
});
// build condition
var queryCondition = { where: { updated_at: { between: [lowerbound,upperbound] } }, limit: 3 };
if(FailedIDs.length > 0){
queryCondition = {
where: Sequelize.and({ updated_at: { between: [lowerbound,upperbound] } },
Sequelize.or(
{ id: FailedIDs }
))
}
}
//////////////////////////////
// get Phoenix Transactions //
//////////////////////////////
PhoenixTransaction
.findAll(queryCondition)
.then(function(poenixTrx){
async.each(poenixTrx, function(value, next){
Transaction.findOne({ where: { id: value.id }})
.then(function(result){
if(!result || result.length === 0){
transactionsToUpdate.push(value);
console.log('!result || result.length === 0')
}
else if(result && result.length === 1){
if(result.hash != value.hash){
transactionsToUpdate.push(value);
console.log('result.hash != poenixTrx[i].hash')
}
}
next();
})
.catch(function(err) {
console.log(err)
})
}, function(err) {
//Return the array transactionsToUpdate in your callback for further use
return callback(err, transactionsToUpdate);
});
})
.catch(function(err){
throw new Error("Something went wrong getting PhoenixTransaction")
})
})
}
Which would be the way with a callback.
But you need make your mind up what you want to use: callback OR promises. Don't use both together (as in: If your method expects a callback it shouldn't return a promise or if it returns a promise it shouldn't expect a callback).
Additional if you use callback you don't want to throw errors, you just call the callback and give the error in the callback - whoever uses your method can check the error from the callback and handle it.
Hope that kinda makes sense to you, I know the whole callback and promises thing is a little strange if you come from something like php and it needs some getting used to :)
thanks for explaining the differences. I think working with promises is the way forward, because it makes the code look nicer and avoids this "callback hell".
For example:
PhoenixSyncTransactions.getlasttransactions(lastTimeSynced,null)
.then(function(res){
return PersistTransaction.prepareTransactions(res).then(function(preparedTrx){
return preparedTrx;
})
}).then(function(preparedTrx){
return PersistTransaction.persistToDB(preparedTrx).then(function(Processes){
return Processes;
})
})
.then(function(Processes){
return PersistTransaction.checkIfMultiProcess(Processes).then(function(result){
return result;
})
})
.then(function(result){
console.log('All jobs done');
})
The whole code is easier to read.

Multiple Q.all inside function?

I want to send a list of new books to a user. So far the below code works fine. The problem is that I don't want to send a book multiple times, so I want to filter them.
Current code works fine:
function checkActiveBooks(books) {
var queue = _(books).map(function(book) {
var deferred = Q.defer();
// Get all alerts on given keywords
request('http://localhost:5000/books?l=0&q=' + book.name, function(error, response, body) {
if (error) {
deferred.reject(error);
}
var books = JSON.parse(body);
if (!_.isEmpty(books)) {
// Loop through users of current book.
var userBooks = _(book.users).map(function(user) {
// Save object for this user with name and deals.
return {
user: user,
book: book.name,
books: books
}
});
if (_.isEmpty(userBooks)) {
deferred.resolve(null);
} else {
deferred.resolve(userBooks);
}
} else {
deferred.resolve(null);
}
});
return deferred.promise;
});
return Q.all(queue);
}
But now I want to filter already sent books:
function checkActiveBooks(books) {
var queue = _(books).map(function(book) {
var deferred = Q.defer();
// Get all alerts on given keywords
request('http://localhost:5000/books?l=0&q=' + book.name, function(error, response, body) {
if (error) {
deferred.reject(error);
}
var books = JSON.parse(body);
if (!_.isEmpty(books)) {
// Loop through users of current book.
var userBooks = _(book.users).map(function(user) {
var defer = Q.defer();
var userBook = user.userBook.dataValues;
// Check per given UserBook which books are already sent to the user by mail
checkSentBooks(userBook).then(function(sentBooks) {
// Filter books which are already sent.
var leftBooks = _.reject(books, function(obj) {
return sentBooks.indexOf(obj.id) > -1;
});
// Save object for this user with name and deals.
var result = {
user: user,
book: book.name,
books: leftBooks
}
return deferred.resolve(result);
});
return Q.all(userBooks);
} else {
deferred.resolve(null);
}
});
return deferred.promise;
});
return Q.all(queue);
}
But above code doesn't work. It doesn't stop looping. I thought it made sense to use q.all twice, because it contains two loops. But I guess I'm doing it wrong...
First of all you should always promisify at the lowest level. You're complicating things here and have multiple deferreds. Generally you should only have deferreds when converting an API to promises. Promises chain and compose so let's do that :)
var request = Q.nfbind(require("request")); // a promised version.
This can make your code in the top section become:
function checkActiveBooks(books) {
return Q.all(books.map(function(book){
return request('http://.../books?l=0&q=' + book.name)
.get(1) // body
.then(JSON.parse) // parse body as json
.then(function(book){
if(_.isEmpty(book.users)) return null;
return book.users.map(function(user){
return {user: user, book: book.name, books: books };
});
});
});
}
Which is a lot more elegant in my opinion.
Now, if we want to filter them by a predicate we can do:
function checkActiveBooksThatWereNotSent(books) {
return checkActiveBooks(books).then(function(books){
return books.filter(function(book){
return checkSentBooks(book.book);
});
});
}
It's worth mentioning that the Bluebird library has utility methods for all this like Promise#filter and Promise#map that'd make this code shorter.
Note that if checkSentBook is asynchronous you'd need to modify the code slightly:
function checkActiveBooksThatWereNotSent(books) {
return checkActiveBooks(books).then(function(books){
return Q.all(books.map(function(book){ // note the Q.all
return Q.all([book, checkSentBooks(book.book)]);
})).then(function(results){
return results.filter(function(x){ return x[1]; })
.map(function(x){ return x[0]; });
});
});
}
Like I said, with different libraries this would look a lot nicer. Here is how the code would look like in Bluebird which is also two orders of magnitude faster and has good stack traces and detection of unhandled rejections. For fun and glory I threw in ES6 arrows and shorthand properties:
var request = Promise.promisify(require("request"));
var checkActiveBooks = (books) =>
Promise.
map(books, book => request("...&q=" + book.name).get(1)).
map(JSON.parse).
map(book => book.users.length ?
book.users.map(user => {user, books, book: book.name) : null))
var checkActiveBooksThatWereNotSent = (books) =>
checkActiveBooks(books).filter(checkBookSent)
Which I find a lot nicer.
Acting on #Benjamins's suggestion, here is what the code would look like when checkSentBooks returns a promise:
var request = Q.nfbind(require("request")); // a promised version.
function checkActiveBooks(books) {
return Q.all(_(books).map(function(book) {
// a callback with multiple arguments will resolve the promise with
// an array, so we use `spread` here
return request('http://localhost:5000/books?l=0&q=' + book.name).spread(function(response, body) {
var books = JSON.parse(body);
if (_.isEmpty(books)) return null;
return Q.all(_(book.users).map(function(user) {
return checkSentBooks(user.userBook.dataValues).then(function(sentBooks) {
// ^^^^^^ return a promise to the array for `Q.all`
return {
user: user,
book: book.name,
books: _.reject(books, function(obj) {
return sentBooks.indexOf(obj.id) > -1;
})
};
});
}));
});
}));
}

Categories

Resources