Naveed Ahmad
Naveed Ahmad

Reputation: 314

how to make a for loop work with a async.parallel()

I am using Sails, Waterline and Async library

function Outerfunction(listOfProducts) {
  var salesOrderId = 1; //some id
  var prom = [];
  for (var i = 0; i < listOfProducts.length; i++) {
    var qty = listOfProducts[i].quantity;
    var prod = listOfProducts[i].productName;
    var update = function(qty, prod, SalesOrderId) {
      CardImages.update({
          where: {
            productName: prod,
            isSold: false,
            readyToSell: true
          }
        }, {
          order: SalesOrderId,
          isSold: true
        })
        .exec(function(err, updatedRecords) {
          if (err) return err;
          return updatedRecords;
        });
    }
    prom.push(update);
  }
  async.parallel(prom, function(err, result) {

    //this callback never gets called
    console.log("database calls done");
  });
}

I am trying to update database with a for loop, this code works fine and updates the database but but my callback with async.parallel won't get called when all the records are updated.

Upvotes: 3

Views: 4156

Answers (1)

Igor Raush
Igor Raush

Reputation: 15240

The function you are looking for is async.map, which will apply an asynchronous function to each element in an array, and call back with an array of results. I can't test this, but something like this should work:

function OuterFunction(listOfProducts) {
  var salesOrderId = 1;  // some id

  async.map(listOfProducts, function (product, done) {
    // for each product, update its DB entry
    CardImages.update({
      productName: product.productName,
      isSold: false,
      readyToSell: true
    }, {
      order: salesOrderId,
      isSold: true
    }).exec(done);  // indicate that async work is done
  }, function (err, result) {
    // all finished
    console.log('database calls done');
  });
}

Note that this solution does not use Promises at all. This is simply callback-based asynchronous work.


I have not worked with Waterline, but based on what I quickly found in the (rather bad) documentation, this is also a possible solution:

function OuterFunction(listOfProducts) {
  var salesOrderId = 1;  // some id
  // extract product names
  var productNames = listOfProducts.map(function (product) {
    return product.productName;
  });

  // update in bulk
  CardImages.update({
    productName: productNames,
    isSold: false,
    readyToSell: true
  }, {
    order: salesOrderId,
    isSold: true
  }).exec(function (err, results) {
    // all finished
    console.log('database calls done');
  });
}

Translated to SQL, the first solution would emit (roughly)

UPDATE table SET isSold = TRUE, readyToSell = FALSE
WHERE productName = 'product 1' AND isSold = FALSE AND readyToSell = TRUE;

UPDATE table SET isSold = TRUE, readyToSell = FALSE
WHERE productName = 'product 2' AND isSold = FALSE AND readyToSell = TRUE;

UPDATE table SET isSold = TRUE, readyToSell = FALSE
WHERE productName = 'product 3' AND isSold = FALSE AND readyToSell = TRUE;

...

and the second would emit the more efficient

UPDATE table SET isSold = TRUE, readyToSell = FALSE
WHERE productName IN ('product 1', 'product 2', 'product 3', ...)
  AND isSold = FALSE AND readyToSell = TRUE;

Upvotes: 2

Related Questions