graydam
graydam

Reputation: 269

How to Group JavaScript Array of Object based on key

So I have a data like this

const carts = [
  {
    name: 'Voucher A',
    participants: [
      {
        date: 112
      },
      {
        date: 112
      }
    ],
    supplierName: 'ABC',
    ticketDescription: 'Description of',
    ...data
  },
  {
    name: 'Voucher B',
    participants: [
      {
        date: 111
      },
      {
        date: 112
      }
    ],
    supplierName: 'ABC',
    ticketDescription: 'Description of',
    ...data
  }
]

And I want to group it based on the date (if it has same date). So for data above, the expected result will be

expected = [
  {
    name: 'Voucher A',
    date: 1,
    count: 1,
    supplierName: 'ABC',
    ticketDescription: 'Description of',
    ...data
  },
  {
    name: 'Voucher A',
    date: 2,
    count: 1,
    supplierName: 'ABC',
    ticketDescription: 'Description of',
    ...data
  }
]

Because it has different date. But if it has same date, the expected result will be

expected = [
  {
    name: 'Voucher A',
    date: 1,
    count: 2,
    supplierName: 'ABC',
    ticketDescription: 'Description of',
    ...data
  }
]

I was trying to use reduce to group it but it did not give the structure I want

carts.forEach(cart => {
  cart.participants.reduce((acc, obj) => {
    acc[obj.date] = [...acc[obj.date] || [], obj]
    return acc
  }, {})
})

Upvotes: 1

Views: 71

Answers (3)

Siva Kondapi Venkata
Siva Kondapi Venkata

Reputation: 11001

Use forEach and destructuring

const process = ({ participants, name }) => {
  const res = {};
  participants.forEach(({ date }) => {
    res[date] ??= { name, count: 0, date };
    res[date].count += 1;
  });
  return Object.values(res);
};


const carts = [
  {
    name: "Voucher A",
    participants: [
      {
        date: 1,
      },
      {
        date: 2,
      },
    ],
  },
];
console.log(carts.flatMap(process));

const carts2 = [
  {
    name: "Voucher A",
    participants: [
      {
        date: 1,
      },
      {
        date: 1,
      },
    ],
  },
];
console.log(carts2.flatMap(process));

Upvotes: 1

Naren
Naren

Reputation: 4470

If you want use, just plain for loops, you can try this solution. It looks simple and elegant 😜😜

const carts = [
  {
    name: 'Voucher A',
    participants: [
      {
        date: 1
      },
      {
        date: 1
      },
      {
        date: 2
      }
    ]
  },
  {
    name: 'Voucher B',
    participants: [
      {
        date: 1
      },
      {
        date: 2
      },
      {
        date: 2
      }
    ]
  }
]

const finalOutput = []

for (const cart of carts) {
  for (const participant of cart.participants) {
     const res = finalOutput.find(e => e.name === cart.name && e.date === participant.date)
     if (res) {
        res.count += 1
     } else {
       finalOutput.push({ name: cart.name, date: participant.date, count: 1 })
     }
  }
}

console.log(finalOutput)

Upvotes: 1

CertainPerformance
CertainPerformance

Reputation: 370729

To organize the data, I think you need two associations to group by: the name and the dates and their counts for that name:

const carts = [
  {
    name: 'Voucher A',
    participants: [
      {
        date: 1
      },
      {
        date: 2
      }
    ]
  }
];

const groupedByNames = {};
for (const { name, participants } of carts) {
  if (!groupedByNames[name]) groupedByNames[name] = {};
  for (const { date } of participants) {
    groupedByNames[name][date] = (groupedByNames[name][date] || 0) + 1;
  }
}
const output = Object.entries(groupedByNames).flatMap(
  ([name, dateCounts]) => Object.entries(dateCounts).map(
    ([date, count]) => ({ name, date: Number(date), count })
  )
);
console.log(output);

Upvotes: 1

Related Questions