Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 355
Naveed Ahmad Avatar asked Mar 17 '26 04:03

Naveed Ahmad


1 Answers

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;
like image 123
Igor Raush Avatar answered Mar 18 '26 18:03

Igor Raush



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!