'How to transform a dataset and aggregate values with javascript/typescript

I want to take a dataset which is an object where the the value field has an array value. I want to iterate through the array and group them by the different ids. I also want it to get an aggregate of "count"(total count) and have a field for the different type of "status" and its associated count.

    "value": [
        {
        "count": 5,
        "id": "id1",
        "status": 1
        },
        {
        "count": 2,
        "id": "id1",
        "status": 3
        },
        {
        "count": 2,
        "id": "id1",
        "status": 4
        },
        {

        "count": 1,
        "id": "id2",
        "status": 0
        },
        {
        "count": 2,
        "id": "id2",
        "status": 1
        },
        {
        "count": 7,
        "id": "id2",
        "status": 2
        },
        {
        "count": 5,
        "id": "id2",
        "status": 3
        },
        {
        "count": 3,
        "id": "id2",
        "status": 4
        }
    ]
}```

desired output is a map where the keys are ids and value is made up of totalCount(aggregate of all the counts of that id), statusx(where x is the different type of status. There will be a limited type of status. Maybe 5 or so) that has the count of that status, and "status" to show what type of status it is(0-5):

{
    id1 : { totalCount: 9, status1 : 5, status3: 2, status4:2},
    id2 : { totalCount: 18, status0 : 1, status1 : 2, status2: 7, status3: 5, status4:3}
}


Solution 1:[1]

Super specific and weird ask, but here ya go. You can do this easily with the reduce method:

const object = {
    value: [
        {
            count: 5,
            id: 'id1',
            status: 1,
        },
        {
            count: 2,
            id: 'id1',
            status: 3,
        },
        {
            count: 2,
            id: 'id1',
            status: 4,
        },
        {
            count: 1,
            id: 'id2',
            status: 0,
        },
        {
            count: 2,
            id: 'id2',
            status: 1,
        },
        {
            count: 7,
            id: 'id2',
            status: 2,
        },
        {
            count: 5,
            id: 'id2',
            status: 3,
        },
        {
            count: 3,
            id: 'id2',
            status: 4,
        },
    ],
};

interface Output {
    [key: string]: {
        totalCount: number;
        [key: string]: number;
    };
}

const group = ({ value }: typeof object) => {
    return value.reduce((acc: Output, { count, id, status }) => {
        if (!acc[id]) acc[id] = { totalCount: count };
        else acc[id].totalCount += count;

        if (!acc[id][`status${status}`]) acc[id][`status${status}`] = 1
        else acc[id][`status${status}`] += 1

        return acc;
    }, {} as Output);
};

console.dir(group(object));

Compiled:

"use strict";
const object = {
    value: [
        {
            count: 5,
            id: 'id1',
            status: 1,
        },
        {
            count: 2,
            id: 'id1',
            status: 3,
        },
        {
            count: 2,
            id: 'id1',
            status: 4,
        },
        {
            count: 1,
            id: 'id2',
            status: 0,
        },
        {
            count: 2,
            id: 'id2',
            status: 1,
        },
        {
            count: 7,
            id: 'id2',
            status: 2,
        },
        {
            count: 5,
            id: 'id2',
            status: 3,
        },
        {
            count: 3,
            id: 'id2',
            status: 4,
        },
    ],
};
const group = ({ value }) => {
    return value.reduce((acc, { count, id, status }) => {
        if (!acc[id])
            acc[id] = { totalCount: count };
        else
            acc[id].totalCount += count;
        if (!acc[id][`status${status}`])
            acc[id][`status${status}`] = 1;
        else
            acc[id][`status${status}`] += 1;
        return acc;
    }, {});
};
console.dir(group(object));

Solution 2:[2]

This is written in TypeScript. You can refer to: https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html if you want to learn more about the 'index access types'

Edit: https://stackblitz.com/edit/typescript-cbfodv, working stackblitz code is available here.

   const dataArray = [
      {
        count: 5,
        id: 'id1',
        status: 1,
      },
      {
        count: 2,
        id: 'id1',
        status: 3,
      },
      {
        count: 2,
        id: 'id1',
        status: 4,
      },
      {
        count: 1,
        id: 'id2',
        status: 0,
      },
      {
        count: 2,
        id: 'id2',
        status: 1,
      },
      {
        count: 7,
        id: 'id2',
        status: 2,
      },
      {
        count: 5,
        id: 'id2',
        status: 3,
      },
      {
        count: 3,
        id: 'id2',
        status: 4,
      },
    ];

var obj: { [k: string]: any } = {};

dataArray.forEach((elem) => {
  let foundGroup = obj[elem.id];
  let statusPropertyName = 'status' + elem.status;

  if (foundGroup === undefined) {
    obj[elem.id] = {
      totalCount: elem.count,
      [statusPropertyName]: elem.count,
    };
  } else {
    foundGroup['totalCount'] += elem.count;
    let foundStatus = foundGroup[statusPropertyName];

    if (foundStatus === undefined) {
      foundGroup[statusPropertyName] = elem.count;
    } else {
      foundStatus += elem.count;
    }
  }
});

console.log(obj);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 mstephen19
Solution 2