Reputation: 71
I have an array with user IDs and I need to find out what name belongs to each ID and return them in an array. I can get the user's name from the database, using knex and push them into an array, but when I try to send the data it is always an empty array.
I am not really good with Promises so can't figure out how to apply to my project.
const userId = [10,11,12,13]
let users = []
userId.map(id => {
db.select('name').from('users').where('user_id', id)
.then(user => {
users.push(user)
})
})
res.json(users)
I want the response to wait until the looping finishes and send the users array.
Upvotes: 1
Views: 533
Reputation: 2576
You want Promise.all()
, see here.
Try
const userId = [10,11,12,13]
let users = userId.map(id => new Promise(resolve => {
db.select('name').from('users').where('user_id', id)
.then(user => {
resolve(user)
})
}))
Promise.all(users).then(()=>res.json(users))
Here users
is an array of promises. As soon as all of them are resolved, do res.json(users)
.
Upvotes: 0
Reputation: 622
First you need to wait for all promises to finish before running res.json(...)
Second, you shouldn't mutate outside variables after promise resolving (the order by which the promises resolve will alter your output and that is not nice.
Something like this should work fine
const userId = [10,11,12,13]
// map userId array to promise array
// Promise.all aggregates a promise array into one big promise that resolves when all promises resolve (and preserves array order)
Promise.all(
userId.map(id =>
db
.select("name")
.from("users")
.where("user_id", id)
)
)
.then(users => res.json(users))
.catch(e => console.error("Error::", e));
/*handle error in the catch block*/
/* visual example of Promise.all.then block
Promise.all([ users = [
getUser(10), -> {userId: 10, ....}
getUser(11), -> {userId: 11, ....}
getUser(12) -> {userId: 12, ....}
]) ]
*/
Upvotes: 1
Reputation: 82096
As an alternative answer, here's how you could make 1 trip to the DB for this particular query meaning you don't need to wait for multiple Promises and reduce the load on your DB
knex.raw(
'select name from users where user_id in (' + userId.map(_ => '?').join(',') + ')',
[...userId]
);
Upvotes: 1
Reputation: 1074208
Your map
is creating an array of undefined
because your callback function doesn't return anything. If we tweak it slightly, it'll create an array of promises, which conveniently is exactly what Promise.all
expects. :-) So:
const userId = [10,11,12,13]
Promise.all(
userId.map(id => db.select('name').from('users').where('user_id', id))
)
.then(users => { // `users` is an array of users, in the same order as the IDs
res.json(users);
})
.catch(error => {
// Render an error response
});
Upvotes: 3