laminatefish
laminatefish

Reputation: 5246

NodeJS Promises can't edit existing 'model'

Edit Upon closer inspection, it would appear that async.forEach finishes before getCurrencies is even run the first time... How do I resolve this? I thought returning a promise would essentially 'chain' these promises together?

I have the below code, which attempts to read transactions from mysql. Due to the size of the table and the length of time query takes, I'm breaking it up and using promises to populate an object. However, getCurrencies doesn't update the model's currencyCode - Yet, both console.log report correct values. Can someone explain what I'm doing wrong please? I'm quite new to promises still. Thanks.

main object building

    connection.query(query).then(function(items) {
        async.forEach(items, function(element) {
            element.ptype = 'merchants';
            element.type = 'transactions';
            element.currencyCode = null;

            getCurrencies(element.currencies_id).then(function(result) {
                console.log(result.currencyCode);
                element.currencyCode = result.currencyCode;
                console.log(JSON.stringify(element));
            });
        });

        res.send(items);
    });

getCurrencies

function getCurrencies(transactionId) {
    var currencies_query = '';
    currencies_query += 'SELECT ';
    currencies_query += 'iso_code AS currencyCode, ';
    currencies_query += 'name AS `currencyName`, ';
    currencies_query += 'symbol AS `currencySymbol`, ';
    currencies_query += 'exponent AS `currencyExponent`, ';
    currencies_query += 'iso_num AS `currencyNumber` ';
    currencies_query += 'FROM ';
    currencies_query += 'currencies ';
    currencies_query += 'WHERE ';
    currencies_query += 'id = ' + transactionId;

    return new Promise(function(resolve, reject) {
        connection.query(currencies_query).then(function(rows) {
            resolve(rows[0]);
        });
    });
};

And output from both console.logs

first

GBP

second

{"id":11213595,"pid":100856,"uri":"/rest/transactions/11213595","puri":"/rest/merchants/100856","path":"/resellers/1/customers/5/merchants/100856/transactions/11213595","transactionID":11213595,"currencies_id":1,"transactionUri":"/rest/transactions/11213595","ptype":"merchants","type":"transactions","currencyCode":"GBP"}

resulting api response from postman

{
    "id": 11213615,
    "pid": 103845,
    "uri": "/rest/transactions/11213615",
    "puri": "/rest/merchants/103845",
    "path": "/resellers/1/customers/2368/merchants/103845/transactions/11213615",
    "transactionID": 11213615,
    "currencies_id": 1,
    "transactionUri": "/rest/transactions/11213615",
    "ptype": "merchants",
    "type": "transactions",
    "currencyCode": null
  }

As you can see, currencyCode is still null - Why?! :(

Upvotes: 0

Views: 56

Answers (1)

Denis Lisitskiy
Denis Lisitskiy

Reputation: 1345

As you can see, currencyCode is still null - Why?! :(

I didn't work with "async.forEach" before but I think, that currencyCode is Null - because you call promise "getCurrencies", whith work asynchronously

If you need to respond to client with result of work few promises - you have to collect promises to array, and then call Promise.all (which will return array of results of all promises)

And you should send response in next block of chain. I think it should work

connection.query(query)
.then(function(items) {
    var arPromises = [];
    async.forEach(items, function(element) {
        element.ptype = 'merchants';
        element.type = 'transactions';
        element.currencyCode = null;
        arPromises.push(
            new Promise(function (resolve, reject) {
                getCurrencies(element.currencies_id)
                    .then(function(result) {
                        element.currencyCode = result.currencyCode;
                        resolve(element);
                    }).catch(function (error) {
                        //do something with error
                        if(error)
                           reject(error);
                    });
            })
        );
    });
    return Promise.all(arPromises);
}).then(function(items){
    res.send(items);
}).catch(function (error) {
    if(error)
     console.log(error);
});

And my advice, finish chain with "catch" block - for avoid lost errors

Upvotes: 1

Related Questions