Link to home
Start Free TrialLog in
Avatar of Giorgio Todeschini
Giorgio TodeschiniFlag for Italy

asked on

How to modify an object inside a Promise

I'm developing a REST API server using Nodejs and Hapi (https://hapi.dev/) framework and Sequelize (https://sequelize.org/) to access to a MYSQL database.

I have the following route function handler:
async function workload(request, h) {

   // First I perform a query and I get a resultset
   const result = await this.userModel.findAll(options);
   // Then I would like to replace the "task" property of each record with a result of another query
   const tasks = result.map(row => {
      const user = row.get();
      user.tasks = []; // Initialize with an empty array
      const user_tasks = this.taskModel.findAll({
         attributes: [ "week",             [ Sequelize.fn("SUM", Sequelize.col('`Task`.`ore_prev`')), "estimatedHours" ] ],
         where: {
            week: { [Op.and]: [ { [Op.gte]: startWeek }, { [Op.lte]: endWeek } ]}
         },
         include: {
            model: this.projectSubphaseUserModel,
            attributes: [],
            where: {
               user: user.id
            }
         },
         group: [ 'week' ],
         raw: true
      })
      .then(function (value) {
                
         user.tasks.push(value); // Fill the array with the result of the subquery
         return user;
      })
      .finally(() => {
         console.log(user.tasks); // Here I found the array properly filled
      });

      return user;
   });

   return h.response(tasks);
}

Open in new window


Unfortunately, in the result of the function, I get the task array empty (like the following).

[
  {
    "id": 276,
    "role": 4,
    "initials": "JD",
    "name": "John Doe",
    "tasks": []
  }
]

Open in new window

Now, I understood that the problem is that when the array has filled by the nested findAll function, the main function has already returned his result with the array still empty.

This (I think) because the nested findAll(...) function is asynchronous, but I can't find a way to wait that the elaboration is finished before to execute the line "return h.response(tasks);"

Could you please help me?

Avatar of leakim971
leakim971
Flag of Guadeloupe image

Avatar of Giorgio Todeschini

ASKER

Dear @leakim971,
thanks for your help. I tried to follow the  page you sent me, and I changed my code as follows:

const result = await this.userModel.findAll(options);
const tasks = result.map(row => {
   const user = row.get();
   user.tasks = []; // Initialize with an empty array
   const user_tasks = this.taskModel.findAll({
         attributes: [ "week", [ Sequelize.fn("SUM", Sequelize.col('`Task`.`ore_prev`')), "estimatedHours" ] ],
         where: {
            week: { [Op.and]: [ { [Op.gte]: startWeek }, { [Op.lte]: endWeek } ]}
         },
         include: {
            model: this.projectSubphaseUserModel,
            attributes: [],
            where: {
               user: user.id
            }
      },
      group: [ 'week' ],
      raw: true
   });

   Promise.all([ user_tasks ]).then((values) => {
      user.tasks.push(values);
   });

   // I would like to pause my code here until the user.tasks have changed by the expression here before

   return user; // Here returns the user before that the user_tasks Promise has executed 
});

Open in new window


Unfortunately, the code of the expression inside the result.map() function returns the user object before that the code inside the function this.taskModel.findAll() changes the value of the task property.

I would like to do this:
  1. Find all my users
    const result = await this.userModel.findAll(options);

    Open in new window

  2. Loop through the users returned by (1) and find the user's tasks
    const user_tasks = this.taskModel.findAll({
             attributes: [ "week", [ Sequelize.fn("SUM", Sequelize.col('`Task`.`ore_prev`')), "estimatedHours" ] ],
             where: {
                week: { [Op.and]: [ { [Op.gte]: startWeek }, { [Op.lte]: endWeek } ]}
             },
             include: {
                model: this.projectSubphaseUserModel,
                attributes: [],
                where: {
                   user: user.id
                }
          },
          group: [ 'week' ],
          raw: true
       });

    Open in new window

  3. To copy the array resulting by (3) to the array of the property user.tasks.

Another try thing that  I tried to do is:

const tasks = result.map(row => {
      const user = row.get();
      user.tasks = []; // Initialize with an empty array
      const user_tasks = await this.taskModel.findAll({
         attributes: [ "week",             [ Sequelize.fn("SUM", Sequelize.col('`Task`.`ore_prev`')), "estimatedHours" ] ],
         where: {
            week: { [Op.and]: [ { [Op.gte]: startWeek }, { [Op.lte]: endWeek } ]}
         },
         include: {
            model: this.projectSubphaseUserModel,
            attributes: [],
            where: {
               user: user.id
            }
         },
         group: [ 'week' ],
         raw: true
      })


      user.tasks = user_tasks;

      return user;
   });

Open in new window

But I get the message "SyntaxError: await is only valid in async function".

Could you please help me?
Thanks in advance
ASKER CERTIFIED SOLUTION
Avatar of Giorgio Todeschini
Giorgio Todeschini
Flag of Italy image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial