Reputation: 27
I'm trying to wait for all of my database calls in a loop to complete before I proceed. I add each call, which are promises, to an array and then use Promise.all()
to wait for all of them. However, there are nested DB calls like user.increment()
or user.create()
which Promise.all()
does not seem to wait for. The output of this snippet usually goes:
User found, incrementing wins...
Promise.all()
User updated
The Promise.all
block is being run before the nested DB calls complete. I feel like I'm missing something really easy.
let dbCalls = [];
for(var i = 0; i < users.length; i++){
let messageUser = users[i];
//try to find user by id
dbCalls.push(db.user.findOne({
where: {
id: messageUser.id
}
}).then(function(user){
if(user){
//found user, increment them
user.increment('wins').then((user) => {
console.log('User found, incrementing wins...');
user.reload();
}).then(user => {
console.log('User updated')
return user;
});
} else{
//user wasn't found, create them
console.log(`${messageUser.username} was not found, creating user...`);
db.user.create({
username: messageUser.username,
id: messageUser.id,
wins: 1
}).then(function(user){
console.log('created user');
return user;
});
}
}).then(res => {
return res;
})
);
}
Promise.all(dbCalls).then(res =>{
console.log('Promise.all()' + res);
});
Upvotes: 2
Views: 1414
Reputation: 370679
You need to chain all of the internal promises to that the item that gets pushed to the array is the full chain. For better readability, consider extracting the increment
and create
to their own function:
const increment = user => user.increment('wins').then((user) => {
console.log('User found, incrementing wins...');
return user.reload();
}).then(user => {
console.log('User updated')
return user;
});
const create = user => {
//user wasn't found, create them
console.log(`${messageUser.username} was not found, creating user...`);
return db.user.create({
username: messageUser.username,
id: messageUser.id,
wins: 1
}).then(user => {
console.log('created user');
return user;
});
};
const dbCalls = users.map(messageUser => db.user.findOne({
where: {
id: messageUser.id
}
}).then(user => (
user
? increment(user)
: create(user)
)));
Promise.all(dbCalls).then(res =>{
console.log('Promise.all()' + res);
});
Upvotes: 0
Reputation: 23029
You forgot to return that promises. So they are not included in your promise chain
Just change lines with db-promises into return user.increment('wins').then((user) => {
Upvotes: 2
Reputation: 3815
Since you are running multiple DB queries that require one to finish before the other one, you should look in NODE.js waterfall calls. It allows promises to be used and you can set which ones require other to finish first before firing.
https://www.npmjs.com/package/promise-waterfall
there is one good example
This library goes as far as even allowing you to wait for a returned value to use in another async call.
Upvotes: 0