Sadique Here
Sadique Here

Reputation: 53

How to group array by month - javascript

I have to group my array by month with key name.

Here is my array and expected result array.

Please help.

var data = [
        { 
          _id: "59d34fabe0a967636c7642f2", 
          date: "2019-10-20T18:30:00.000Z", 
        }, 
        { 
          _id: "59d34fab9d1a05ca06ef9775", 
          date: "2019-12-20T18:30:00.000Z", 
        }, 
        { 
          _id: "59d34fab4d49dc45357ab3a5", 
          date: "2019-12-25T18:30:00.000Z", 
        }, 
        { 
          _id: "59d34fab5aa903089e1f9a44", 
          date: "2019-11-24T18:30:00.000Z", 
        }
      ]

Expected Result :

var result= [
        {
          "2019-10-01" :
          [
            {
              _id: "59d34fabe0a967636c7642f2", 
              date: "2019-10-20T18:30:00.000Z", 
            },
          ] 
        },
        {
          "2019-11-01" :
          [
            { 
              _id: "59d34fab5aa903089e1f9a44", 
              date: "2019-11-24T18:30:00.000Z", 
            }
          ] 
        },
        {
          "2019-12-01" :
          [
            { 
              _id: "59d34fab9d1a05ca06ef9775", 
              date: "2019-12-20T18:30:00.000Z", 
            }, 
            { 
              _id: "59d34fab4d49dc45357ab3a5", 
              date: "2019-12-25T18:30:00.000Z", 
            }
          ] 
        },
      ]

Update enter image description here .......................................................................................................

Upvotes: 1

Views: 2233

Answers (3)

stacj
stacj

Reputation: 1120

Something like this?

const data = [ { _id: "59d34fabe0a967636c7642f2", date: "2019-10-20T18:30:00.000Z", }, { _id: "59d34fab9d1a05ca06ef9775", date: "2019-12-20T18:30:00.000Z", }, { _id: "59d34fab4d49dc45357ab3a5", date: "2019-12-25T18:30:00.000Z", }, { _id: "59d34fab5aa903089e1f9a44", date: "2019-11-24T18:30:00.000Z", } ];


const sortedObj = {};
data.forEach(e => {                    // loop over all elements
  const k = e.date.slice(0, 7);        // key in YYYY-MM (e.g. 2019-10)
  const fk = `${k}-01`;                // key with appended '-01'   
  sortedObj[fk] = sortedObj[fk] || []; // create new entry if no value for key exists
  sortedObj[fk].push(e);               // add key to existing list
});

const sortedArr = Object.entries(sortedObj).sort((a,b) => new Date(a[0]) - new Date(b[0]));

console.log(sortedArr);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Or as one-liner:

const data = [ { _id: "59d34fabe0a967636c7642f2", date: "2019-10-20T18:30:00.000Z", }, { _id: "59d34fab9d1a05ca06ef9775", date: "2019-12-20T18:30:00.000Z", }, { _id: "59d34fab4d49dc45357ab3a5", date: "2019-12-25T18:30:00.000Z", }, { _id: "59d34fab5aa903089e1f9a44", date: "2019-11-24T18:30:00.000Z", } ];

const sorted = (a = {}, data.forEach(e => { b = e.date.slice(0, 7); c = `${b}-01`; a[c] = a[c] || []; a[c].push(e); }), a = Object.entries(a).sort((a,b) => new Date(a[0]) - new Date(b[0])), a);
console.log(sorted);

Upvotes: 3

Kinglish
Kinglish

Reputation: 23664

A simple reduce loop does the trick. The whole tamale is going to be formatted by Object.fromEntries() which essentially takes our finished array and converts it to an array of objects with key/value pairs. The inner loop is encased in Object.entries which allows us to iterate the object like an array. The sort is a localeCompare of the date properties.

const months = Object.fromEntries( // convert our final result back into key/values pairs
  Object.entries(data.reduce((b, a) => {  // convert to an iterable array
  let m = a.date.split("T")[0].substr(0, 7) + "-01"; // set up date property for grouping
  if (b.hasOwnProperty(m)) b[m].push(a); else b[m] = [a];  // create or add to accumulating group
  return b; }, {}))
  .sort((a,b) => a[0].localeCompare(b[0]))) // sort by date property

var data = [{
    _id: "59d34fabe0a967636c7642f2",
    date: "2019-10-20T18:30:00.000Z",
  },
  {
    _id: "59d34fab9d1a05ca06ef9775",
    date: "2019-12-20T18:30:00.000Z",
  },
  {
    _id: "59d34fab4d49dc45357ab3a5",
    date: "2019-12-25T18:30:00.000Z",
  },
  {
    _id: "59d34fab5aa903089e1f9a44",
    date: "2019-11-24T18:30:00.000Z",
  }
]
//Object.fromEntries(
const months = Object.entries(data.reduce((b, a) => {
  let m = a.date.split("T")[0].substr(0, 7) + "-01";
  if (b.hasOwnProperty(m)) b[m].push(a); else b[m] = [a];
  return b; }, {}))
  .sort((a,b) => a[0].localeCompare(b[0]))
  .map(e => ({[e[0]]:e[1]}));
console.log(months)

Upvotes: 3

Hassan Imam
Hassan Imam

Reputation: 22574

You can use array#reduce to group your data based on month and year in an object accumulator. Then extract all values using Object.values(). Then, sort the result based on the date key.

const data = [{ _id: "59d34fabe0a967636c7642f2", date: "2019-10-20T18:30:00.000Z", }, { _id: "59d34fab9d1a05ca06ef9775", date: "2019-12-20T18:30:00.000Z", }, { _id: "59d34fab4d49dc45357ab3a5", date: "2019-12-25T18:30:00.000Z", }, { _id: "59d34fab5aa903089e1f9a44", date: "2019-11-24T18:30:00.000Z", } ],
    grouped = Object.values(data.reduce((r, o) => {
      const date = `${o.date.substr(0,7)}-01`;
      r[date] ||= {[date]: []};
      r[date][date].push(o);
      return r;
    }, []))
    .sort((a,b) => Object.keys(a)[0].localeCompare(Object.keys(b)[0]));
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 0

Related Questions