Search code examples
javascriptarraysfor-loopasync-awaites6-promise

How to make your code wait for execution of loop


Following is my getUser function

const getUsers = async (req, res) => {
    try {
        ddb.get({
            TableName: "Tablename",
            Key: { Username: req.query.username }
        },(err,user) => {
            if(err || Object.keys(user).length === 0) {
                return res.status(404).json("Something went wrong")
            } else {
                const userSociety = Object.keys(user.Item.Societies)[0]
                ddb.get({
                    TableName: "Tablename",
                    Key: { SocietyCode: userSociety }
                },(err, society) => {
                    if(err || Object.keys(society).length === 0) {
                        return res.status(400).json({ message: "Could not fetch society members" })
                    } else {
                        const users = Object.keys(society.Item.SocietyMembers)
                        const usersData = []
                         users.forEach(async u => {
                            ddb.get({
                                TableName: "TestMyMohallaUsers",
                                Key: { Username: u }
                            },async (err,user) => {
                                if(err || Object.keys(user).length === 0) {
                                } else usersData.push({
                                    Username: user.Item.Username,
                                    Firstname: user.Item.Name
                                })
                            })
                        })
                        return res.status(200).json({ message: "Data detched successfully", Users: usersData })
                    }
                })
            }
        })
    } catch (error) {
        return res.status(500).json({ error: "Internal Server Error" })
    }
}

I want to wait for the execution of forEach and then send back the data via return statement but as of now the return statement gives empty array of users.

Clearly my code in not waiting for the execution of forEach and then returning the data. How can I do that someone help me?

Edit: ddb is an instance of DynamoDB


Solution

  • You'll have a better time if you

    • use the DynamoDB Promise API instead of a pyramid of callbacks
    • refactor your code to a couple of functions
    • Finally, awaiting for all user fetches to complete requires Promise.all for all of those promises.
    async function getUser(ddb, username) {
      const user = await ddb
        .get({
          TableName: "TestMyMohallaUsers",
          Key: { Username: username },
        })
        .promise();
      if (!user.Item) {
        throw new Error(`User ${username} not found`);
      }
      return user.Item;
    }
    
    async function getSociety(ddb, societyCode) {
      const society = await ddb
        .get({
          TableName: "Tablename",
          Key: { SocietyCode: societyCode },
        })
        .promise();
      if (!society.Item) {
        throw new Error(`Society ${societyCode} not found`);
      }
      return society.Item;
    }
    
    const getUsers = async (req, res) => {
      try {
        const user = await getUser(ddb, req.params.username);
        const userSocietyCode = Object.keys(user.Societies)[0];
        const society = await getSociety(ddb, userSocietyCode);
        const societyUsers = Object.keys(society.SocietyMembers);
        const usersData = await Promise.all(
          societyUsers.map(async (member) => {
            const user = await getUser(ddb, member);
            return {
              Username: user.Username,
              Firstname: user.Name,
            };
          }),
        );
        return res
          .status(200)
          .json({
            message: "Data detched successfully",
            Users: usersData,
          });
      } catch (e) {
        return res
          .status(400)
          .json({ message: `Could not fetch information: ${e}` });
      }
    };