NodeJS: TypeError: undefined is not a function - Promise.all - Object.keys

375
August 27, 2017, at 10:27 AM

I'd need your help because I get the typeError mentionned in the question and I'm not sure to understand why. I've got an object (that comes back from a request-promise) that looks like this:

{
                   "statusCode": 200,
                   "body": {
                      "BTC_USD": {
                         "buy_price": "4258",
                         "sell_price": "4265",
                         "last_trade": "4265",
                         "high": "4360",
                         "low": "4200",
                         "avg": "4260.2077946",
                         "vol": "219.32404491",
                         "vol_curr": "933982.49730504",
                         "updated": 1503767188
                      },
                      "BTC_EUR": {
                         "buy_price": "3640.1001",
                         "sell_price": "3650",
                         "last_trade": "3644.8",
                         "high": "3801.999999",
                         "low": "3622.000006",
                         "avg": "3685.0414084",
                         "vol": "94.48595035",
                         "vol_curr": "347993.56447153",
                         "updated": 1503767128
                      },
                      "BTC_RUB": {
                         "buy_price": "243511",
                         "sell_price": "244340",
                         "last_trade": "243511.49870226",
                         "high": "248786.99",
                         "low": "239630",
                         "avg": "243430.47675799",
                         "vol": "140.12303781",
                         "vol_curr": "34185015.26771479",
                         "updated": 1503767190
                      },
                      "BTC_UAH": {
                         "buy_price": "107000",
                         "sell_price": "107790",
                         "last_trade": "107790",
                         "high": "109900",
                         "low": "105354",
                         "avg": "108167.30195869",
                         "vol": "34.94251977",
                         "vol_curr": "3770330.73968614",
                         "updated": 1503767167
                      },
                      "DASH_BTC": {
                         "buy_price": "0.08528559",
                         "sell_price": "0.08644069",
                         "last_trade": "0.086196",
                         "high": "0.093364",
                         "low": "0.07043",
                         "avg": "0.0803689",
                         "vol": "1595.2753788",
                         "vol_curr": "123.76291968",
                         "updated": 1503767189
                      },
                   },
                   "request": {
                      "uri": {
                         "protocol": "https:",
                         "slashes": true,
                         "auth": null,
                         "host": "api.exmo.com",
                         "port": 443,
                         "hostname": "api.exmo.com",
                         "hash": null,
                         "search": null,
                         "query": null,
                         "pathname": "/v1/ticker/",
                         "path": "/v1/ticker/",
                         "href": "https://api.exmo.com/v1/ticker/"
                      },
                      "method": "GET",
                      "headers": {
                         "accept": "application/json"
                      }
                  }
                }

as you can see, the body has multiple objects and my goal is to rearrange the info in a new layout for each body.keys:

Object.keys(res.body).forEach((k) => {
          result= {
            mk: 'exmo',
            name: k,
            a: res.body[k].sell_price,
            b: res.body[k].buy_price,
            c: res.body[k].last_trade,
            v: res.body[k].vol,
            t: res.body[k].vol_curr,
            l: res.body[k].low,
            h: res.body[k].high,
            sn: res.body[k].updated,
          }
        });
        return result;

But for some reason it's not working... I feel like I'm not using the Promise.all properly?

Here's my full code for testing (it reproduces the error):

function exmo() {
  Promise.all(
    function () {
        var result = {};
        var res = {
                   "statusCode": 200,
                   "body": {
                      "BTC_USD": {
                         "buy_price": "4258",
                         "sell_price": "4265",
                         "last_trade": "4265",
                         "high": "4360",
                         "low": "4200",
                         "avg": "4260.2077946",
                         "vol": "219.32404491",
                         "vol_curr": "933982.49730504",
                         "updated": 1503767188
                      },
                      "BTC_EUR": {
                         "buy_price": "3640.1001",
                         "sell_price": "3650",
                         "last_trade": "3644.8",
                         "high": "3801.999999",
                         "low": "3622.000006",
                         "avg": "3685.0414084",
                         "vol": "94.48595035",
                         "vol_curr": "347993.56447153",
                         "updated": 1503767128
                      },
                      "BTC_RUB": {
                         "buy_price": "243511",
                         "sell_price": "244340",
                         "last_trade": "243511.49870226",
                         "high": "248786.99",
                         "low": "239630",
                         "avg": "243430.47675799",
                         "vol": "140.12303781",
                         "vol_curr": "34185015.26771479",
                         "updated": 1503767190
                      },
                      "BTC_UAH": {
                         "buy_price": "107000",
                         "sell_price": "107790",
                         "last_trade": "107790",
                         "high": "109900",
                         "low": "105354",
                         "avg": "108167.30195869",
                         "vol": "34.94251977",
                         "vol_curr": "3770330.73968614",
                         "updated": 1503767167
                      },
                      "DASH_BTC": {
                         "buy_price": "0.08528559",
                         "sell_price": "0.08644069",
                         "last_trade": "0.086196",
                         "high": "0.093364",
                         "low": "0.07043",
                         "avg": "0.0803689",
                         "vol": "1595.2753788",
                         "vol_curr": "123.76291968",
                         "updated": 1503767189
                      },
                   },
                   "request": {
                      "uri": {
                         "protocol": "https:",
                         "slashes": true,
                         "auth": null,
                         "host": "api.exmo.com",
                         "port": 443,
                         "hostname": "api.exmo.com",
                         "hash": null,
                         "search": null,
                         "query": null,
                         "pathname": "/v1/ticker/",
                         "path": "/v1/ticker/",
                         "href": "https://api.exmo.com/v1/ticker/"
                      },
                      "method": "GET",
                      "headers": {
                         "accept": "application/json"
                      }
                  }
                }
        Object.keys(res.body).forEach((k) => {
          result= {
            mk: 'exmo',
            name: k,
            a: res.body[k].sell_price,
            b: res.body[k].buy_price,
            c: res.body[k].last_trade,
            v: res.body[k].vol,
            t: res.body[k].vol_curr,
            l: res.body[k].low,
            h: res.body[k].high,
            sn: res.body[k].updated,
          }
        });
        return result;
    }).then((data) => {
    console.log(JSON.stringify(data, null, 3));
  })
};
exmo();

thanks in advance to you all for your help!

***** EDIT *****: [Trying to clarify] My objective was to get a single object per iteration of forEach. Ultimately each of these object would go into a mongo database. I'm using incorrectly Promise.all (because it needs an array of promises) but was looking for a similar solution.

Answer 1

Your question is complicated a little by your code being all lumped in together, so here I've split it up.

This function mimics your server response as an example to show you how the promise can be managed.

function getData() {
  return new Promise((resolve, reject) => {
    // Parse the returned data
    resolve(JSON.parse(res));
  });
}

Then you need to transform your data. Here you can use map to iterate over the obj instead of forEach:

function mapData(obj) {
  return Object.keys(obj.body).map((k) => {
    return {
      mk: 'exmo',
      name: k,
      a: res.body[k].sell_price,
      b: res.body[k].buy_price,
      c: res.body[k].last_trade,
      v: res.body[k].vol,
      t: res.body[k].vol_curr,
      l: res.body[k].low,
      h: res.body[k].high,
      sn: res.body[k].updated
    }
  });
}

Then you can simply call getData, mapData, and then output the result. You don't want Promise.all here because that method only accepts an array of promises.

getData()
  .then(mapData)
  .then(data => console.log(JSON.stringify(data, null, 3)));

DEMO (n.b. this demo uses your parsed obj so doesn't reparse it again in getData).

Answer 2

As you can see, you're reassigning result over and over in the sane loop forEach(), the return at the end could only return the information of the last key in body.
What you need to do is to put all values with the same key in an array (maybe?). Or in a simpler way: transpose the whole table.
Therefore, you gotta declare bunch of Array's at the first place:

// init
let result = { };
let keys = ['buy_price', 'sell_price', /* etc. */];
keys.forEach(k => result[k] = []);
// gathering informations
Object.keys(res.body).forEach(name =>
    Object.keys(res.body[name]).forEach(k => result[k].push(res.body[name][k]))
);

Now you can easily get your information by the index from result.

If you want to index'em by their original names, you can firstly initialize result as a bunch of Object's, then use the name instead of directly push() in the inner forEach().

Object.keys(res.body[name]).forEach(k => result[k][name] = res.body[name][k])

Which makes more sense on 'transposing' the whole table.

Answer 3

Promise.all(iterable) it take an iterable object such as an Array or String.

I modified your code, it's giving output. Note :- your code logic i did't not change, it give result as your logic.

function exmo() { 
  var data = (function () { 
        var result = {}; 
        var res = { 
                   "statusCode": 200, 
                   "body": { 
                      "BTC_USD": { 
                         "buy_price": "4258", 
                         "sell_price": "4265", 
                         "last_trade": "4265", 
                         "high": "4360", 
                         "low": "4200", 
                         "avg": "4260.2077946", 
                         "vol": "219.32404491", 
                         "vol_curr": "933982.49730504", 
                         "updated": 1503767188 
                      }, 
                      "BTC_EUR": { 
                         "buy_price": "3640.1001", 
                         "sell_price": "3650", 
                         "last_trade": "3644.8", 
                         "high": "3801.999999", 
                         "low": "3622.000006", 
                         "avg": "3685.0414084", 
                         "vol": "94.48595035", 
                         "vol_curr": "347993.56447153", 
                         "updated": 1503767128 
                      }, 
                      "BTC_RUB": { 
                         "buy_price": "243511", 
                         "sell_price": "244340", 
                         "last_trade": "243511.49870226", 
                         "high": "248786.99", 
                         "low": "239630", 
                         "avg": "243430.47675799", 
                         "vol": "140.12303781", 
                         "vol_curr": "34185015.26771479", 
                         "updated": 1503767190 
                      }, 
                      "BTC_UAH": { 
                         "buy_price": "107000", 
                         "sell_price": "107790", 
                         "last_trade": "107790", 
                         "high": "109900", 
                         "low": "105354", 
                         "avg": "108167.30195869", 
                         "vol": "34.94251977", 
                         "vol_curr": "3770330.73968614", 
                         "updated": 1503767167 
                      }, 
                      "DASH_BTC": { 
                         "buy_price": "0.08528559", 
                         "sell_price": "0.08644069", 
                         "last_trade": "0.086196", 
                         "high": "0.093364", 
                         "low": "0.07043", 
                         "avg": "0.0803689", 
                         "vol": "1595.2753788", 
                         "vol_curr": "123.76291968", 
                         "updated": 1503767189 
                      }, 
                   }, 
                   "request": { 
                      "uri": { 
                         "protocol": "https:", 
                         "slashes": true, 
                         "auth": null, 
                         "host": "api.exmo.com", 
                         "port": 443, 
                         "hostname": "api.exmo.com", 
                         "hash": null, 
                         "search": null, 
                         "query": null, 
                         "pathname": "/v1/ticker/", 
                         "path": "/v1/ticker/", 
                         "href": "https://api.exmo.com/v1/ticker/" 
                      }, 
                      "method": "GET", 
                      "headers": { 
                         "accept": "application/json" 
                      } 
                  } 
                } 
        Object.keys(res.body).forEach((k) => { 
          result= { 
            mk: 'exmo', 
            name: k, 
            a: res.body[k].sell_price, 
            b: res.body[k].buy_price, 
            c: res.body[k].last_trade, 
            v: res.body[k].vol, 
            t: res.body[k].vol_curr, 
            l: res.body[k].low, 
            h: res.body[k].high, 
            sn: res.body[k].updated, 
          } 
        }); 
        return result; 
    }); 
     
    Promise.all([data()]).then((data) => { 
    console.log(JSON.stringify(data, null, 3)); 
  }) 
}; 
 
exmo(); 
 
<!-- begin snippet: js hide: false console: true babel: false -->

READ ALSO
Recommended way to grow a Buffer?

Recommended way to grow a Buffer?

Let's say I am constructing a string, or series of bytes, of variable length, in NodeThe documentation for buf

192
Mongo(ose) returning array of object Object [duplicate]

Mongo(ose) returning array of object Object [duplicate]

This question already has an answer here:

185
Closing connection, but not display message

Closing connection, but not display message

I have the following code and it works, but not display message 'too big file'I see a chrome screen with ERR_CONNECTION_RESET

233
Adding items according to object&#39;s value

Adding items according to object's value

This is the code i currently have:

155