node.jsasynchronousasync-awaitpromisepromise.all

Use async await with Array.map not working


I've used this approach, it should give me the Expected Output which I've mentioned below. But, due to asynchronous execution, it is giving the Actual Output. So, Please help me to solve the same.

See, I'm calling one async function, inside i'm running three nested map loops. And in the third loop I'm connecting the database and fetching values. Based on the value, I'm generating the values of the Object which is empty at the first. And once the function called, it is triggering the then method.That's where the problem arises, I need that then function to be executed after the called function executed completely. This is the complete problem statement

Given the following code:

 let messageObject = {};
 async function storeManager() {
  // storing the defects or modifying
  console.log('hii from storeManager()');
  await Promise.all(
    Object.keys(filledDefects).map((defectName) => {
      Object.keys(filledDefects[defectName]).map((subDefectName) => {
        Object.keys(filledDefects[defectName][subDefectName]).map(
          async (zone) => {
            const result = await dbConnectedPool.query(
              `SELECT * FROM defect_table WHERE body_number=${enteredBodyNumber} AND category='${selectedCategory}' AND subcategory='${selectedSubCategory}' AND defect='${defectName}' AND subdefect='${subDefectName}' AND zone = ${zone.replace(
                '_',
                ''
              )}`
            );

            if (result.rows.length == 0) {
              // block to save defects record for the first time
              console.log(
                `INSERT INTO defect_table (body_number,mode,category,subcategory,defect,subdefect,zone,defectCount,date,time,username) VALUES (${enteredBodyNumber},'${mode}','${selectedCategory}','${selectedSubCategory}','${defectName}','${subDefectName}',${zone.replace(
                  '_',
                  ''
                )},${
                  filledDefects[defectName][subDefectName][zone]
                },'${date}','${time}','${username}');`
              );
              await dbConnectedPool.query(
                `INSERT INTO defect_table (body_number,mode,category,subcategory,defect,subdefect,zone,defectCount,date,time,username) VALUES (${enteredBodyNumber},'${mode}','${selectedCategory}','${selectedSubCategory}','${defectName}','${subDefectName}',${zone.replace(
                  '_',
                  ''
                )},${
                  filledDefects[defectName][subDefectName][zone]
                },'${date}','${time}','${username}');`
              );

              mod.set(
                messageObject,
                `Newly Saved Zone.${zone}.${defectName}.${subDefectName}`,
                filledDefects[defectName][subDefectName][zone]
              );
              console.log('inside: ', messageObject);
            } else {
              // block to modify existing defect records

              console.log(
                `UPDATE defect_table SET defectCount=${
                  filledDefects[defectName][subDefectName][zone]
                },date='${date}',time='${time}',username='${username}' WHERE body_number=${enteredBodyNumber} AND category='${selectedCategory}' AND subcategory='${selectedSubCategory}' AND defect='${defectName}' AND subdefect='${subDefectName}' AND zone=${zone.replace(
                  '_',
                  ''
                )}`
              );

              await dbConnectedPool.query(
                `UPDATE defect_table SET defectCount=${
                  filledDefects[defectName][subDefectName][zone]
                },date='${date}',time='${time}',username='${username}' WHERE body_number=${enteredBodyNumber} AND category='${selectedCategory}' AND subcategory='${selectedSubCategory}' AND defect='${defectName}' AND subdefect='${subDefectName}' AND zone=${zone.replace(
                  '_',
                  ''
                )}`
              );

              mod.set(
                messageObject,
                `Overwritten Zone.${zone}.${defectName}.${subDefectName}`,
                filledDefects[defectName][subDefectName][zone]
              );
              console.log('inside: ', messageObject);
            }
            // checking whether already record exists with same aspects
          }
        );
      });
    })
  );
  console.log('bye from storeManager()');
}

storeManager().then(() => {
  console.log('message outside:', messageObject);
});

Expected Output:

hii from storeManager()
bye from storeManager()
UPDATE defect_table SET defectCount=12,date='2022-10-12',time='12:52:33',username='Vasanth' 
  WHERE body_number=1234 AND category='LH SHELL BODY MAIN-LINE' AND subcategory='FENDER - LH 
  SBML' AND defect='Surface' AND subdefect='Dent' AND zone=210
inside:  { 'Overwritten Zone': { _210: { Surface: [Object] } } }
UPDATE defect_table SET defectCount=12,date='2022-10-12',time='12:52:33',username='Vasanth' 
  WHERE body_number=1234 AND category='LH SHELL BODY MAIN-LINE' AND subcategory='FENDER - LH 
  SBML' AND defect='Surface' AND subdefect='Dent' AND zone=215
inside:  {
  'Overwritten Zone': { _210: { Surface: [Object] }, _215: { Surface: [Object] } }
}
message outside: {
  'Overwritten Zone': { _210: { Surface: [Object] }, _215: { Surface: [Object] } }
}

Actuall Output:

hii from storeManager()
bye from storeManager()
message outside: {}
UPDATE defect_table SET defectCount=12,date='2022-10-12',time='12:52:33',username='Vasanth' 
  WHERE body_number=1234 AND category='LH SHELL BODY MAIN-LINE' AND subcategory='FENDER - LH 
  SBML' AND defect='Surface' AND subdefect='Dent' AND zone=210
inside:  { 'Overwritten Zone': { _210: { Surface: [Object] } } }
UPDATE defect_table SET defectCount=12,date='2022-10-12',time='12:52:33',username='Vasanth' 
  WHERE body_number=1234 AND category='LH SHELL BODY MAIN-LINE' AND subcategory='FENDER - LH 
  SBML' AND defect='Surface' AND subdefect='Dent' AND zone=215
inside:  {
  'Overwritten Zone': { _210: { Surface: [Object] }, _215: { Surface: [Object] } }
}

Solution

  • You'll need to use Promise.all everywhere you are producing an array of promises, not just on the outermost call. And you'll need to make the map callbacks actually return those promises!

    await Promise.all(Object.entries(filledDefects).map(async ([defectName, defect]) => {
      await Promise.all(Object.entries(defect).map(async ([subDefectName, subDefect]) => {
        await Promis.all(Object.entries(subDefect).map(async ([zoneName, zone]) => {
          await …;
        }));
      }));
    }));
    

    Alternatively you can also write this without some of the async/await:

    await Promise.all(Object.entries(filledDefects).map(([defectName, defect]) =>
      Promise.all(Object.entries(defect).map(async ([subDefectName, subDefect]) =>
        Promis.all(Object.entries(subDefect).map(async ([zoneName, zone]) => {
          await …;
        }));
      ));
    ));