Home > Software design >  Function returning result before fulfilling all the promises
Function returning result before fulfilling all the promises

Time:10-30

I am trying to return an array of objects after retrieving data from two separate collections in mongodb.

Since two collections are connected through foreign key, I am trying to do some async await operation to get data one after another and return the result after fulfilling all promises.

But the getCommentDetails function is returning an empty array before running the forEach loop.

const getCommentDetails = async (id) => {
  const commentDetails = [];

  const comments = await commentsCollection
    .find({ complain_id: id })
    .toArray();

  comments.forEach(async (comment) => {
    const user = await usersCollection.findOne({
      _id: ObjectId(comment.user_id),
    });

    commentDetails.push({
      _id: comment._id,
      complainId: comment.complain_id,
      userId: comment.user_id,
      comment: comment.comment,
      name: user.name,
      date: comment.createdAt,
    });
  });

  return commentDetails;// it returns []
};


const getComments = async (req, res, next) => {
  const id = req.params.id;
  try {
    const data = await getCommentDetails(id);
    return res.json(data);
  } catch (error) {
    console.log(error);
  }
};

CodePudding user response:

The forEach method is firing off multiple asynchronous executions, so the getCommentDetails function returns undefined before all those executions end.

Please, use for...of instead.

Try the following JavaScript code instead:

const getCommentDetails = async (id) => {
  const commentDetails = [];

  const comments = await commentsCollection
    .find({ complain_id: id })
    .toArray();

  for (const comment of comments) {
    const user = await usersCollection.findOne({
      _id: ObjectId(comment.user_id),
    });

    commentDetails.push({
      _id: comment._id,
      complainId: comment.complain_id,
      userId: comment.user_id,
      comment: comment.comment,
      name: user.name,
      date: comment.createdAt,
    });
  }

  return commentDetails;// it returns []
};


const getComments = async (req, res, next) => {
  const id = req.params.id;
  try {
    const data = await getCommentDetails(id);
    return res.json(data);
  } catch (error) {
    console.log(error);
  }
};

CodePudding user response:

You can't await promises in a forEach like that. You need to use Promise.all, which will execute the promises in paralell:

// ...

const commentDetails = await Promise.all(comments.map(async (comment) => {
    const user = await usersCollection.findOne({
      _id: ObjectId(comment.user_id),
    });

    return {
      _id: comment._id,
      complainId: comment.complain_id,
      userId: comment.user_id,
      comment: comment.comment,
      name: user.name,
      date: comment.createdAt,
    };
  }));

 return commentDetails;

If you need to do the promises serially, you need a for ... of loop instead.

  • Related