Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Group array of objects by two properties

I’m trying to group array of objects by two properties so I get data on two levels. This is in JavaScript – Node server.
Here is the data I’m starting with

items = [
  {month: 11, year: 2022, amount: 10},
  {month: 12, year: 2022, amount: 6},
  {month: 11, year: 2022, amount: 7},
  {month: 12, year: 2022, amount: 12},
  {month: 1, year: 2023, amount: 5},
  {month: 1, year: 2023, amount: 15},
  {month: 11, year: 2023, amount: 30},
  {month: 11, year: 2023, amount: 20}
],

I need all items from the same month and in the same year grouped together. The final result would look like this:

result = {
  "2022": {
    "11": [
      {month: 11, year: 2022, amount: 10},
      {month: 11, year: 2022, amount: 7}
    ],
    "12": [
      {month: 12, year: 2022, amount: 6},
      {month: 12, year: 2022, amount: 12}
    ]
  },
  "2023": {
    "11": [
      {month: 11, year: 2023, amount: 30},
      {month: 11, year: 2023, amount: 20}
    ],
    "1": [
      {month: 1, year: 2023, amount: 5},
      {month: 1, year: 2023, amount: 15}
    ]
  }
}

The first step is done quite easily, either through reduce or groupBy(), I’ve opted for groupBy() because it is cleaner:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

const itemsPerYear = items.groupBy(item => { return item.year })

This gives me intermediate result:

itemsPerYear = {
  "2022": [
      {month: 11, year: 2022, amount: 10},
      {month: 11, year: 2022, amount: 7},
      {month: 12, year: 2022, amount: 6},
      {month: 12, year: 2022, amount: 12}
    ],
  "2023": [
      {month: 11, year: 2023, amount: 30},
      {month: 11, year: 2023, amount: 20},
      {month: 1, year: 2023, amount: 5},
      {month: 1, year: 2023, amount: 15}
    ]
}

So if I apply similar logic and go with:

const itemsPerMonth = Object.values(itemsPerYear).groupBy(item => { return item.month })

I get:

[Object: null prototype] {
  undefined: [
    [ [Object], [Object], [Object], [Object] ],
    [ [Object], [Object], [Object], [Object] ]
  ]
}

I get a step closer with ForEach:
const itemsPerMonth = Object.values(itemsPerYear).forEach(sub => { console.log(sub) })
I get:

[
    {month: 11, year: 2022, amount: 10},
    {month: 11, year: 2022, amount: 7},
    {month: 12, year: 2022, amount: 6},
    {month: 12, year: 2022, amount: 12}
],
[
    {month: 11, year: 2023, amount: 30},
    {month: 11, year: 2023, amount: 20},
    {month: 1, year: 2023, amount: 5},
    {month: 1, year: 2023, amount: 15}
]

If I want to use groupBy() inside the ForEach() I get undefined.

Thanks

>Solution :

Here is a quick solution using a .reduce():

const input = [ {month: 11, year: 2022, amount: 10}, {month: 12, year: 2022, amount: 6}, {month: 11, year: 2022, amount: 7}, {month: 12, year: 2022, amount: 12}, {month: 1, year: 2023, amount: 5}, {month: 1, year: 2023, amount: 15}, {month: 11, year: 2023, amount: 30}, {month: 11, year: 2023, amount: 20} ];

const result = input.reduce((acc, obj) => {
  if(!acc[obj.year]) acc[obj.year] = {};
  if(!acc[obj.year][obj.month]) acc[obj.year][obj.month] = [];
  acc[obj.year][obj.month].push(obj);
  return acc;
}, {});
console.log('result:', result);

Docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading