Search code examples
javascriptpromisesequelize.jses6-promiseecmascript-5

Unable to resolve promise chain


I am trying to write a Sequelize migration script win which I am trying to update my database but it is having many asynchronous operations (database queries and then updating database with particular id)

Here is my code

return db.organizationEntries
      .findAll()
      .then((entries) => {
        return entries.forEach(entry => {
          console.log(entry);
          db.organizationEntries
            .findAll({
              attributes: [
                [
                  db.sequelize.fn(
                    'MAX',
                    db.sequelize.col('organizationEntries.serial_number')
                  ),
                  'maximum_serial_no'
                ]
              ],
              where: {
                organizationId: entry.organizationId
              }
            })
            .then(orgEntry => {
              console.log(orgEntry[0].dataValues.maximum_serial_no);
              let data = { serialNumber: orgEntry[0].dataValues.maximum_serial_no + 1 };
              console.log(data)

              //problem 
              db.organizationEntries.update(data, {
                where: {
                  id: entry.id
                }
              })
                .then((result) => {
                  console.log(result);

                })
            });
          // promises.push(promise);
        });
        // return Promise.all(promises);
      }) 

Actually what I am trying to do is I am trying to take the list of all orgEntries from the database and then I am finding maximum serial number for that organization_id and then updating that particular orgEntry and like this all these operations in a loop

Now the problem is coming all the things are going in order but after finding max_serial_no it is not updating the database and I am not able to resolve what I should do to make that asynchronous call work in this order


Solution

  • I think you can solve this in two ways:

    Simultaneously Promises

    In a following code I removed forEach in favor of Promise.all() and map()

    • The map() method create (and return) a new array with the results of calling a provided function on every element in the calling array.

    Example:

    let numbers = [1, 2, 3]
    let doubledNumbers = numbers.map(n => n * 2)
    // doubledNumbers [2, 4, 6]
    
    • The Promise.all() method take an array of Promises as argument and returns a single Promise that will be resolved when all promises will be resolved or rejected if one promise failed

    Example:

    let promise1 = findUserById(5)
    let promise2 = findUserFriends(5)
    Promise.all([promise1, promise2])
    .then(values => {
      // values: [user object, list of user friends]
    })
    

    Result:

    db.organizationEntries.findAll()
    .then(entries => {
      return Promise.all(entries.map(entry => {
        console.log(entry)
    
        return db.organizationEntries.findAll({
          where: {
            organizationId: entry.organizationId
          },
          attributes: [
            [
              db.sequelize.fn('MAX', db.sequelize.col('organizationEntries.serial_number')),
              'maximum_serial_no'
            ]
          ]
        })
        .then(orgEntry => {
          console.log(orgEntry[0].dataValues.maximum_serial_no)
          let data = { serialNumber: orgEntry[0].dataValues.maximum_serial_no + 1 }
          console.log(data)
          return db.organizationEntries.update(data, { where: { id: entry.id } })
        })
      }))
    })
    .then(result => {
      // result: Array of updated organizationEntries
      console.log(result)
    })
    

    Step by step Promises with reduce() method

    • The reduce() method applies a function against an accumulator and each element in the array (from left to right) to reduce it to a single value. (from MDN web docs)

    Example:

    let items = [{ name: 'pencil', price: 2 }, { name: 'book', price: 10 }]
    let total = items.reduce((total, item) => total += item.price, 0)
    // total: 12
    

    Result:

    db.organizationEntries.findAll()
    .then(entries => {
      return entries.reduce((previousPromise, entry) => {
        console.log(entry)
    
        return previousPromise
        .then(_ => {
          return db.organizationEntries.findAll({
            where: {
              organizationId: entry.organizationId
            },
            attributes: [
              [
                db.sequelize.fn('MAX', db.sequelize.col('organizationEntries.serial_number')),
                'maximum_serial_no'
              ]
            ]
          })
        })
        .then(orgEntry => {
          console.log(orgEntry[0].dataValues.maximum_serial_no)
          let data = { serialNumber: orgEntry[0].dataValues.maximum_serial_no + 1 }
          console.log(data)
          return db.organizationEntries.update(data, { where: { id: entry.id } })
        })
        .then(updatedEntry => {
          console.log(updatedEntry)
        })
      }, Promise.resolve())
    })
    .then(result => {
      // result: Last updated organization entry
      console.log('finished')
    })