Saurabh
Saurabh

Reputation: 1662

How to handle this javascript asynchronous function

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

Upvotes: 1

Views: 78

Answers (3)

Dharmaraj
Dharmaraj

Reputation: 50830

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;
};

Upvotes: 2

beto
beto

Reputation: 87

How 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

Upvotes: 1

ram12393
ram12393

Reputation: 1258

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

Upvotes: 1

Related Questions