nb_nb_nb
nb_nb_nb

Reputation: 1381

Format grouped data from JSON data

I am trying to format the grouped data that I got from JSON but having trouble doing that.

This is my array of objects:

arr = [
            {
                "date": "2020-01-01",
                "metric": 32,
                "type": "Google"
            },
            {
                "date": "2020-01-01",
                "metric": 24,
                "type": "Bing"
            },
            {
                "date": "2020-01-02",
                "metric": 1,
                "type": "Google"
            },
            {
                "date": "2020-01-02",
                "metric": 32,
                "type": "Jeeves"
            },
            {
                "date": "2020-01-03",
                "metric": 24,
                "type": "Bing"
            },
            {
                "date": "2020-01-03",
                "metric": 30,
                "type": "Google"
            }
          ]

I want to group all the metrics by date. So I did this:

const groupBy = (array, key) => {
    return array.reduce((result, currentValue) => {
      (result[currentValue[key]] = result[currentValue[key]] || []).push(currentValue);
      return result;
    }, {});
};

const personGroupedByColor = groupBy(arr, 'date');

When I do this:

2020-01-01: 
0: {date: "2020-01-01", metric: 32, type: "Google"}
1: {date: "2020-01-01", metric: 24, type: "Bing"}
2020-01-02: 
0: {date: "2020-01-02", metric: 1, type: "Google"}
1: {date: "2020-01-02", metric: 32, type: "Jeeves"}
2020-01-03: 
0: {date: "2020-01-03", metric: 24, type: "Bing"}
1: {date: "2020-01-03", metric: 30, type: "Google"}

Is there any way for me to format the data to look like so:

{"date_val": "2020-01-01", "metric_name": [32, 24]}
{"date_val": "2020-01-02", "metric_name": [1, 32]}
{"date_val": "2020-01-03", "metric_name": [24, 30]}

How can I format it to look like this? My data is dynamic so I want to be able to hardcode as less as possible.

Upvotes: 2

Views: 307

Answers (3)

mickl
mickl

Reputation: 49975

You can use array.reduce and dynamically evaluate result keys based on specified fields:

let arr = [
            {
                "date": "2020-01-01",
                "metric": 32,
                "type": "Google"
            },
            {
                "date": "2020-01-01",
                "metric": 24,
                "type": "Bing"
            },
            {
                "date": "2020-01-02",
                "metric": 1,
                "type": "Google"
            },
            {
                "date": "2020-01-02",
                "metric": 32,
                "type": "Jeeves"
            },
            {
                "date": "2020-01-03",
                "metric": 24,
                "type": "Bing"
            },
            {
                "date": "2020-01-03",
                "metric": 30,
                "type": "Google"
            }
          ];
          
  let group = (arr, val, name) => arr.reduce((acc, curr) => {
      let valKey = val +"_val";
      let nameKey = name + "_name";
      let valValue = curr[val];
      let nameValue = curr[name];
      
      let existing = acc.find(x => x[valKey] === valValue);
      if(existing){
         existing[nameKey].push(nameValue);
      } else {
         acc.push({[valKey]: valValue, [nameKey]: [nameValue]})
      }
      return acc;
  }, []);
  
  console.log(group(arr, 'date', 'metric'))

Upvotes: 1

Alex Khristo
Alex Khristo

Reputation: 487

Do something like that

  Object.entries(personGroupedByColor).map(([key, group]) => ({
    ['date_val']: key,
    ['metric_name']: group.map(entry => entry.metric),
  }))

Upvotes: 2

Luís Ramalho
Luís Ramalho

Reputation: 10208

You could reduce() the array and check if a given date is already in the accumulator, if so, push the current date to it, otherwise create a new object with that date in the array:

arr = [{
    date: "2020-01-01",
    metric: 32,
    type: "Google",
  },
  {
    date: "2020-01-01",
    metric: 24,
    type: "Bing",
  },
  {
    date: "2020-01-02",
    metric: 1,
    type: "Google",
  },
  {
    date: "2020-01-02",
    metric: 32,
    type: "Jeeves",
  },
  {
    date: "2020-01-03",
    metric: 24,
    type: "Bing",
  },
  {
    date: "2020-01-03",
    metric: 30,
    type: "Google",
  },
];

let result = arr.reduce((p, c) => {
  let match = p.find(o => o.date_val === c.date);
  if (match) {
    match.metric_name.push(c.metric)
  } else {
    p.push({
      date_val: c.date,
      metric_name: [c.metric],
    });
  }
  return p;
}, []);

console.log(result);

Upvotes: 1

Related Questions