skip to Main Content

I am using node js and fetching data from a url that returns a list of 28000+ JSON objects. I want to map each objects identifier to one of its sub-objects. Every example of mapping in JS I look at is expecting the JSON to be in a key value format like "id:value"

The JSON data im getting is

  '28338': {
    high: 696000000,
    highTime: 1691191991,
    low: 672500000,
    lowTime: 1691190341
  }

I want to create a map of 28338:high.

Every top level field (28338) is uniquely named so I cant just say map ID:high since that field isnt called ID. Its called 28338. And on item id 28337 the field is called 28337 etc. 1-28000+ So Id need to map 28000+ times.

My end goal is to fetch the latest item prices from the URL and then create a map of them like 28338:696000000 so I can later loop through it and update a sqlite db. update items SET itemValue = ? where itemID = ? (high,28338).

But right now I cant even build the map of objects.

async function getData() {
    const url = 'https://prices.runescape.wiki/api/v1/osrs/latest';
    const response = await fetch(url);
    const jsonResponse = await response.json();
    console.log(jsonResponse);
  
    return Object.keys(jsonResponse).reduce((result, key) => {
      result[key] = jsonResponse[key].high;
      return result;
    }, {})
} 
const myList = await getData();

When I test this in a console and I console.log(myList) it returns { data: undefined }

3

Answers


  1. You can use Object.entries() and reduce() to achieve what you want:

    async function getData() {
      const url = 'https://prices.runescape.wiki/api/v1/osrs/latest';
      const response = await fetch(url);
      const jsonResponse = await response.json();
    
      return Object.entries(jsonResponse.data).reduce(
        (agg, [key, { high }]) => (agg[key] = high, agg),
        {}
      );
    }
    
    getData().then(console.log);
    /* Stackoverflow: show only console */
    
    .as-console-wrapper {
      max-height: 100% !important;
      top: 0;
    }

    The idea is simple: You can get an array of arrays which contain key-value pairs using Object.entries(), then you just have to build up a new object with the key and the high property of the value.

    The callback reduce() has two relevant arguments for us here. The aggregated value (here agg) and the current value of the iteration. For the current value we use quite a bit of descructuring. We know we get an array like this from Object.entries() [key, value] so we can destructure like this right away, so we already have the key of our new object. Additionally we also need the high property value from the value. We know value looks like this:

    {
        high: 696000000,
        highTime: 1691191991,
        low: 672500000,
        lowTime: 1691190341,
    }
    

    So we can just use object destructuring to obtain the one value we’re interested in like this { high }.

    The rest is straightforward: we assign the key with the value high to our new object agg and return agg so it can be passed to us again in the next iteration. In the end we’ll end up with the expected result.

    Of course you do not have to use destructuring or just some. So the callback in reduce() could also look like this (all are identical in functionality):

    // Without desctructuring
    (agg, keyValue) => (agg[keyValue[0]] = keyValue[1].high, agg)
    
    // With destructuring the array (which I would recommend, since I think it is more readable)
    (agg, [key, value]) => (agg[key] = value.high, agg)
    
    // Also destructure the value
    (agg, [key, { high }]) => (agg[key] = high, agg)
    
    Login or Signup to reply.
  2. Your response has the data of interest in a data property. So you need to get the key/values from that property.

    NB: I prefer using Object.fromEntries in place of reduce, but it is not essential:

    async function getData() {
        const url = 'https://prices.runescape.wiki/api/v1/osrs/latest';
        const response = await fetch(url);
        const jsonResponse = await response.json();
    
        return Object.fromEntries(Object.entries(jsonResponse.data).map(
            ([key, {high}]) => [key, high]
        ));
    } 
    
    
    getData().then(console.log);
    Login or Signup to reply.
  3. A simple way to do this is to aggregate into a new json and return it.

    async function getData() {
        const url = 'https://prices.runescape.wiki/api/v1/osrs/latest';
        const response = await fetch(url);
        const jsonResponse = await response.json();
      
        const aggData = {};
        Object.entries(jsonResponse['data']).forEach(([key, value]) => {
          if (!(key in aggData)) {
            aggData[key] = 0;
          }
          aggData[key] += value['high'];
        })
        return aggData;
    } 
    
    getData().then((d) => console.log(d));
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search