I have this function in javascript node
exports.getUserEmailByAccess = async (moduleType) => {
let emailList = []
const foundUsers = await Access.find({moduleType:moduleType})
console.log(foundUsers);
await foundUsers.forEach(access => {
User.findById(access.userId)
.then(foundUser => {
console.log(foundUser.workerEmail);
emailList.push(foundUser.workerEmail)
})
});
console.log(emailList);
return emailList
}
What I want is to push into emailList array by looping object array, the above approach results in an empty array,so I tried a different following way
exports.getUserEmailByAccess = async (moduleType) => {
let emailList = []
const foundUsers = await Access.find({moduleType:moduleType})
console.log(foundUsers);
await foundUsers.forEach(access => {
const foundUser = User.findById(access.userId)
console.log(foundUser.workerEmail);
emailList.push(foundUser.workerEmail)
});
console.log(emailList);
return emailList
}
By doing this , the array list is getting filled but with an [undefined]strong text value, I come from a humble python control structure background, Please can I know why I am not able to push data into array even after using async/await
3 Answers 3
If the User.findById() returns a promise, I'd recommend using Promise.all() instead of individually running all promises using forEach to fetch documents of all foundUsers:
exports.getUserEmailByAccess = async (moduleType) => {
const foundUsers = await Access.find({ moduleType: moduleType });
console.log(foundUsers);
const userDocs = await Promise.all(
foundUsers.map((user) => User.findById(user.userId))
);
const emailList = userDocs.map((user) => user.workerEmail);
// or alternatively
// const emailList = userDocs.map(({workerEmail}) => workerEmail);
console.log(emailList);
return emailList;
};
Comments
you can give try this
exports.getUserEmailByAccess = async (moduleType) => {
let emailList = []
const foundUsers = await Access.find({ moduleType: moduleType })
console.log(foundUsers);
await foundUsers.map(async access => {
let result = await User.findById(access.userId);
if (result) {
emailList.push(foundUser.workerEmail)
}
});
console.log(emailList);
return emailList
}
UPDATED
await Promise.all(
foundUsers.map(async access => {
let result = await User.findById(access.userId);
if (result) {
emailList.push(foundUser.workerEmail)
}
})
])
console.log(emailList);
return emailList
3 Comments
map won't wait for the async function to be resolved, the emailList will remain empty.await Promise.all(array.map ..... if you want to do things parallelHow are your Models related? I think you might do a populate here if the Access Model has the ObjectId of the User Model. Something like this:
const foundUsers = await Access.find({ moduleType: moduleType }).populate({
path: 'users', // the name of the field which contains the userId
select: '-__v' // fields to bring from database. Can add a (-) to NOT bring that field
})
The idea is that you specify all the fields that you need. Then when you receive the data, you can do something like:
foundUsers.users.email
1 Comment
Explore related questions
See similar questions with these tags.
foundUsers.forEachreturn a Promise - if not, you can't await it ... I'm assuming that is NOT Array forEach, in which case, never use Array forEach with async/await, unless you REALLY know what you're doing - and even then, there's always better ways to do itforEachdoesn't wait for the promise to be resolved, instead you should use aforloop.User.findByIdin parallel or in series