skip to Main Content

Hello I have data given in that kind of form:

 const mockData = [
    {
      id: 1,
      title: 'Lorem ipsum dolor',
      assignee: 'Mr First',
      teams: 'team first',
      dueDate: 'Monday',
      status: 'CLOSE',
    },
    {
      id: 2,
      title: 'Sit amet',
      assignee: 'Mr second',
      teams: 'teams second',
      dueDate: '10/10/2022',
      status: 'OPEN',
    },
  ]

and I need to aggregate them to this kind of shape:

const aggregated = [
    {
      id: 1,
      title: 'title',
      items: [
        'Lorem ipsum dolor',
        'Sit amet',
      ],
    },
    {
      id: 2,
      title: 'assignee',
      items: [
        'Mr second',
        'Mr second',
      ],
    },
    {
      id: 3,
      title: 'teams',
      items: [
        'team first',
        'team second',
      ],
    },
    ...

  ]

But I’m not really sure how to achieve that. Here is my code however there is nothing really to show as it is totally wrong approach I assume because it generates plenty of repeated elements

   const output = mockData.reduce((acc: AgreggatedType, item: ItemType) => {
  Object.keys(item)
    .forEach((key) => {
      if (key) {
        acc.push({
          id: item.id,
          title: key,
          items: [],
        });
      }
    });
  return acc;
}, []);

2

Answers


  1. One way to collect property values for each object, identified by id is as follows:

    const mockData = [{
        id: 1,
        title: "id1-t1",
        assignee: "id1-a1",
        teams: "id1-tm1",
      },
      {
        id: 1,
        title: "id1-t2",
        assignee: "id1-a2",
        teams: "id1-tm2",
      },
      {
        id: 2,
        title: "id2-t1",
        assignee: "id2-a1",
        teams: "id2-tm1",
      },
    ];
    
    const map = mockData.reduce((acc, curr) => {
      if (!acc.has(curr.id)) {
        acc.set(curr.id, {});
      }
    
      const prev = acc.get(curr.id);
    
      for (const [key, value] of Object.entries(curr)) {
        prev[key] = (prev[key] || []).concat(value);
      }
    
      return acc;
    }, new Map());
    
    console.log("1:", map.get(1));
    console.log("2:", map.get(2));

    You can easily modify to strip out the id property values if you choose to.

    Login or Signup to reply.
  2. N.B. This answer assumes that item IDs are unique, and that you are trying to aggregate by property.

    Instead of having an array of result items, you could have a Map of them, keyed by the property name.
    So, for example, { status: ["CLOSE", "OPEN"] } instead of [{ title: "status", items: ["CLOSE", "OPEN"] }].

    I’m not sure what the purpose of the ID in the resulting data was, so I have not included in case I misinterpret it. If it is important beyond simply being part of the data structure you used, please comment. If they were intended to somehow relate to the source item IDs, see the second snippet.

    Here is a basic function that will produce the data structure I described:

    function aggregate(data) {
      const aggregated = new Map()
    
      for (const item of data) {
        for (const [key, value] of Object.entries(item)) {
          if (!aggregated.has(key)) aggregated.set(key, [])
          aggregated.get(key).push(value)
        }
      }
    
      return aggregated
    }
    
    const mockData = [{
        id: 1,
        title: 'Lorem ipsum dolor',
        assignee: 'Mr First',
        teams: 'team first',
        dueDate: 'Monday',
        status: 'CLOSE',
      },
      {
        id: 2,
        title: 'Sit amet',
        assignee: 'Mr second',
        teams: 'teams second',
        dueDate: '10/10/2022',
        status: 'OPEN',
      },
    ]
    
    // The Stack Snippet console can't do Maps.
    console.log(Object.fromEntries(aggregate(mockData).entries()))

    If you need to know the ID of the original item, you can modify it slightly to produce [id, value] pairs:

    function aggregate(data) {
      const aggregated = new Map()
    
      for (const item of data) {
        for (const [key, value] of Object.entries(item)) {
          if (!aggregated.has(key)) aggregated.set(key, [])
          aggregated.get(key).push([item.id, value]) // This is the only change.
        }
      }
    
      return aggregated
    }
    
    const mockData = [{
        id: 1,
        title: 'Lorem ipsum dolor',
        assignee: 'Mr First',
        teams: 'team first',
        dueDate: 'Monday',
        status: 'CLOSE',
      },
      {
        id: 2,
        title: 'Sit amet',
        assignee: 'Mr second',
        teams: 'teams second',
        dueDate: '10/10/2022',
        status: 'OPEN',
      },
    ]
    
    // The Stack Snippet console can't do Maps.
    console.log(Object.fromEntries(aggregate(mockData).entries()))
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search