etcN00b
etcN00b

Reputation: 66

Group array of object by month and year

I have an array that looks like this

myArray = [
  Object {
    "_id": "0c35e243",
    "createdDate": "2021-05-19T08:58:14.497Z",
    "description": "desc text",
  },
  Object {
    "_id": "08e05fcb",
    "createdDate": "2022-07-19T08:42:34.702Z",
    "desc": "desc text2",
  },
  Object {
    "_id": "6a33dca3",
    "createdDate": "2021-07-19T08:35:53.199Z",
    "desc": "desc text3",
  },
  Object {
    "_id": "58ea808d",
    "createdDate": "2022-08-19T08:13:35.516Z",
    "desc": "desc text4",
  },
  Object {
    "_id": "a95b706c",
    "createdDate": "2022-08-19T04:12:44.941Z",
    "desc": "desc text5",
  },
]

I want to sort it by year and month so it would look like this

newArray = [
  "2022" : [
     "7" : [
       Object {
         "_id": "08e05fcb",
         "createdDate": "2022-07-19T08:42:34.702Z",
         "desc": "desc text2",
       }
     ],
     "8" : [
       Object {
         "_id": "58ea808d",
         "createdDate": "2022-08-19T08:13:35.516Z",
         "desc": "desc text4",
       },
       Object {
         "_id": "a95b706c",
         "createdDate": "2022-08-19T04:12:44.941Z",
         "desc": "desc text5",
       },
     ]
  ],
  "2021" : [
     "5" : [
       Object {
         "_id": "0c35e243",
         "createdDate": "2021-05-19T08:58:14.497Z",
         "description": "desc text",
       }
     ],
     "7" : [
       Object {
         "_id": "6a33dca3",
         "createdDate": "2021-07-19T08:35:53.199Z",
         "desc": "desc text3",
       }
     ]
  ]
]

i've been trying to use lodash groupBy

const groupByMonth = groupBy(myArray, ({createdDate})=> new Date(createdDate).getMonth());

with result like this

Object {
  "5": Array [
    Object {
      "_id": "0c35e243",
      "createdDate": "2021-05-19T08:58:14.497Z",
      "description": "desc text",
    },
  ],
  "7": Array [
    Object {
      "_id": "08e05fcb",
      "createdDate": "2022-07-19T08:42:34.702Z",
      "desc": "desc text2",
    },
    Object {
      "_id": "6a33dca3",
      "createdDate": "2021-07-19T08:35:53.199Z",
      "desc": "desc text3",
    },
  ],
  "8": Array [
    Object {
      "_id": "58ea808d",
      "createdDate": "2022-08-19T08:13:35.516Z",
      "description": "desc text4",
    },
    Object {
      "_id": "a95b706c",
      "createdDate": "2022-08-19T04:12:44.941Z",
      "desc": "desc text5",
    },
  ],
}

Now what should i do next? I've tried

const groupByYear = groupBy(groupByMonth, ({_createdDate}) => new Date(_createdDate).getYear());

but i think it's not the solution since it return NaN as the year and it wont group the month like what I expected too

It's okay if the solution is not using lodash as long as the result is look like the expected result also if its possible I would like to use the month name so its not 5,7,8 but May, July, August etc.

Upvotes: 0

Views: 852

Answers (6)

Duy Quoc
Duy Quoc

Reputation: 181

Here is my solution without lodash, and I also convert month of the year from number to short name. Hope can help you

    const myArray = [
      {
        _id: '0c35e243',
        createdDate: '2021-05-19T08:58:14.497Z',
        description: 'desc text'
      },
      {
        _id: '08e05fcb',
        createdDate: '2022-07-19T08:42:34.702Z',
        desc: 'desc text2'
      },
      {
        _id: '6a33dca3',
        createdDate: '2021-07-19T08:35:53.199Z',
        desc: 'desc text3'
      },
      {
        _id: '58ea808d',
        createdDate: '2022-08-19T08:13:35.516Z',
        desc: 'desc text4'
      },
      {
        _id: 'a95b706c',
        createdDate: '2022-08-19T04:12:44.941Z',
        desc: 'desc text5'
      }
    ];
    
    const output = myArray.reduce((acc, cur) => {
      const createdDate = new Date(cur.createdDate)
      const year = createdDate.getFullYear()
      const monthShortName = createdDate.toLocaleString('en-us', { month: 'short' })
    
      // Get year object corresponding to current item from acc (or insert if not present)
      const groupByYear = acc[year] = acc[year] || {};
    
      //Get month array corresponding to current item from groupByYear object (or insert if not present)
      const groupByMonth = groupByYear[monthShortName] = groupByYear[monthShortName] || [];
    
      // Add current item to current groupByMonth array
      groupByMonth.push(cur);
    
      return acc
    }, {});
    
    console.log(output);

Upvotes: 0

Naren Murali
Naren Murali

Reputation: 56410

This is my version.

const myArray = [
  {
    _id: '0c35e243',
    createdDate: '2021-05-19T08:58:14.497Z',
    description: 'desc text',
  },
  {
    _id: '08e05fcb',
    createdDate: '2022-07-19T08:42:34.702Z',
    desc: 'desc text2',
  },
  {
    _id: '6a33dca3',
    createdDate: '2021-07-19T08:35:53.199Z',
    desc: 'desc text3',
  },
  {
    _id: '58ea808d',
    createdDate: '2022-08-19T08:13:35.516Z',
    desc: 'desc text4',
  },
  {
    _id: 'a95b706c',
    createdDate: '2022-08-19T04:12:44.941Z',
    desc: 'desc text5',
  },
];
function transform(data, keyName) {
  const output = [];
  _.forIn(data, (value, key) => {
    value[keyName] = key;
    output.push(value);
  });
  return output;
}
const groupedByYear = _.groupBy(myArray, (item) =>
  moment(item.createdDate).year()
);
const groupedByYearArray = transform(groupedByYear, 'year').sort();
console.log(groupedByYearArray);
const output = groupedByYearArray.map((item) => {
  const groupedByMonth = _.groupBy(myArray, (item) =>
    moment(item.createdDate).month()
  );
  return transform(groupedByMonth, 'month').sort();
});
console.log(output);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.2.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>

Upvotes: 0

Lord Bee
Lord Bee

Reputation: 150

let myArray = [
   {
    "_id": "0c35e243",
    "createdDate": "2021-05-19T08:58:14.497Z",
    "description": "desc text",
  },
   {
    "_id": "08e05fcb",
    "createdDate": "2022-07-19T08:42:34.702Z",
    "desc": "desc text2",
  },
   {
    "_id": "6a33dca3",
    "createdDate": "2021-07-19T08:35:53.199Z",
    "desc": "desc text3",
  },
   {
    "_id": "58ea808d",
    "createdDate": "2022-08-19T08:13:35.516Z",
    "desc": "desc text4",
  },
   {
    "_id": "a95b706c",
    "createdDate": "2022-08-19T04:12:44.941Z",
    "desc": "desc text5",
  },
]

This did the trick for me. I used a package called moment to split the year and month.

const groupByYear = (array) => {
  let group = {}
  array.forEach((elem)=>{
    let year = moment(elem.createdDate).format('YYYY')
    if(!group[year]){
      group[year] = {}
      let month = moment(elem.createdDate).format('MM')
      if(!group[year][month]){
        group[year][month] = [elem]
      }else{
        group[year][month].push(elem)
      }
    }else{
      let month = moment(elem.createdDate).format('MM')
      if(!group[year][month]){
        group[year][month] = [elem]
      }else{
        group[year][month].push(elem)
      }
    }
  })
  return group
}

Upvotes: 0

Sakil
Sakil

Reputation: 652

let myArray = [
    {"_id": "0c35e243", "createdDate": "2021-05-19T08:58:14.497Z", "description": "desc text"},
    {"_id": "08e05fcb", "createdDate": "2022-07-19T08:42:34.702Z", "desc": "desc text2"},
    {"_id": "6a33dca3", "createdDate": "2021-07-19T08:35:53.199Z", "desc": "desc text3"},
    {"_id": "58ea808d", "createdDate": "2022-08-19T08:13:35.516Z", "desc": "desc text4"},
    {"_id": "a95b706c", "createdDate": "2022-08-19T04:12:44.941Z", "desc": "desc text5"},
];

let output = {};
myArray.forEach(elem => {
    let date = new Date(elem.createdDate);
    let year = date.getFullYear();
    let month = date.getMonth() + 1;
    if(output[year]) {
        if(output[year][month]) {
            output[year][month].push(elem);
        } else {
            output[year][month] = [elem];
        }
    } else {
        output[year] = {
            [month]: [elem]
        }
    }
});
console.log(output);

Upvotes: 0

r043v
r043v

Reputation: 1869

let out = {} ;

myArray.forEach( e => {
    const [ year, month ] = e.createdDate.split("-") ;
    out[ year ] ??= {} ;
    out[ year ][ month ] ??= [] ;
    out[ year ][ month ].push( e ) ;
} ) ;

=>

{
  '2021': {
    '05': [
      {
        _id: '0c35e243',
        createdDate: '2021-05-19T08:58:14.497Z',
        description: 'desc text'
      }
    ],
    '07': [
      {
        _id: '6a33dca3',
        createdDate: '2021-07-19T08:35:53.199Z',
        desc: 'desc text3'
      }
    ]
  },
  '2022': {
    '07': [
      {
        _id: '08e05fcb',
        createdDate: '2022-07-19T08:42:34.702Z',
        desc: 'desc text2'
      }
    ],
    '08': [
      {
        _id: '58ea808d',
        createdDate: '2022-08-19T08:13:35.516Z',
        desc: 'desc text4'
      },
      {
        _id: 'a95b706c',
        createdDate: '2022-08-19T04:12:44.941Z',
        desc: 'desc text5'
      }
    ]
  }
}

Upvotes: 4

Đ&#224;o Minh Hạt
Đ&#224;o Minh Hạt

Reputation: 2930

myArray = [
   {
    "_id": "0c35e243",
    "createdDate": "2021-05-19T08:58:14.497Z",
    "description": "desc text",
  },
  {
    "_id": "08e05fcb",
    "createdDate": "2022-07-19T08:42:34.702Z",
    "desc": "desc text2",
  },
   {
    "_id": "6a33dca3",
    "createdDate": "2021-07-19T08:35:53.199Z",
    "desc": "desc text3",
  },
   {
    "_id": "58ea808d",
    "createdDate": "2022-08-19T08:13:35.516Z",
    "desc": "desc text4",
  },
   {
    "_id": "a95b706c",
    "createdDate": "2022-08-19T04:12:44.941Z",
    "desc": "desc text5",
  },
]

const newArray = _.groupBy(myArray, ({ createdDate }) => (new Date(createdDate)).toLocaleString('en-us',{month:'short', year:'numeric'}))

console.log(newArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>

I don't know why you append "_" to "createdDate" tho. It should work this way.

Upvotes: 1

Related Questions