Home > Net >  Monthly sum of level using lodash groupby?
Monthly sum of level using lodash groupby?

Time:02-21

I have like to make some conversions using lodash groupby to an array of objects. Applying to 2 keys clazz_id first and then month resulting in the sum of the level.

import './App.css'
import _ from 'lodash'
import { useEffect } from 'react'
import moment from 'moment'
import groupBy from 'lodash/groupBy'

const data1 = [
  {
    id: 1,
    clazz_id: 1,
    answers: [
      { level: 8, created_at: '2022-01-19T09:13:42.149 08:00' },
      { level: 1, created_at: '2022-02-19T09:13:42.149 08:00' },
    ],
  },
  {
    id: 2,
    clazz_id: 2,
    answers: [
      { level: 7, created_at: '2022-01-19T09:13:42.149 08:00' },
      { level: 2, created_at: '2022-03-19T09:13:42.149 08:00' },
    ],
  },
  {
    id: 3,
    clazz_id: 2,
    answers: [
      { level: 3, created_at: '2022-01-19T09:13:42.149 08:00' },
      { level: 8, created_at: '2022-02-19T09:13:42.149 08:00' },
    ],
  },
]

const App = () => {
  const data2 = []

  useEffect(() => {
    data1.map((item) => {
      item.answers.map((e) => {
        data2.push({
          clazz_id: item.clazz_id,
          level: e.level,
          month: moment(e.created_at).format('MMM'),
        })
      })
    })
    const a = groupBy(data2, 'clazz_id', 'month')
    console.log(a)
  }, [])

  return <div className='App'>test</div>
}

export default App

However, the month was not applied correctly. Any help would be greatly appreciated.

The result should be:

[{clazz_id: 1, level: 8, month: 'Jan'},
{clazz_id: 1, level: 1, month: 'Feb'}]


[{clazz_id: 2, level: 10, month: 'Jan'},
{clazz_id: 2, level: 8, month: 'Feb'},
{clazz_id: 2, level: 2, month: 'Mar'}]

CodePudding user response:

You could get the required result using a couple of calls to Array.reduce(), creating a grouping key based on clazz_id and month.

We then sum the level value for any items that shar the same key:

const data1 = [ { id: 1, clazz_id: 1, answers: [ { level: 8, created_at: '2022-01-19T09:13:42.149 08:00' }, { level: 1, created_at: '2022-02-19T09:13:42.149 08:00' }, ], }, { id: 2, clazz_id: 2, answers: [ { level: 7, created_at: '2022-01-19T09:13:42.149 08:00' }, { level: 2, created_at: '2022-03-19T09:13:42.149 08:00' }, ], }, { id: 3, clazz_id: 2, answers: [ { level: 3, created_at: '2022-01-19T09:13:42.149 08:00' }, { level: 8, created_at: '2022-02-19T09:13:42.149 08:00' }, ], }, ]

const result = Object.values(data1.reduce((acc, { clazz_id, answers }) => { 
    return answers.reduce((acc, { level, created_at }) => {
        const month = moment(created_at).format('MMM');
        const key = `${clazz_id}-${month}`;
        acc[key] = acc[key] || { clazz_id, level: 0, month };
        acc[key].level  = level
        return acc;
    }, acc);
}, {}));

console.log('Result:')
result.forEach(r => console.log(JSON.stringify(r)))
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js" integrity="sha512-qTXRIMyZIFb8iQcfjXWCO8 M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

CodePudding user response:

With plain Javascript, you could reduce with a nested object.

const
    data = [{ id: 1, clazz_id: 1, answers: [{ level: 8, created_at: '2022-01-19T09:13:42.149 08:00' }, { level: 1, created_at: '2022-02-19T09:13:42.149 08:00' }] }, { id: 2, clazz_id: 2, answers: [{ level: 7, created_at: '2022-01-19T09:13:42.149 08:00' }, { level: 2, created_at: '2022-03-19T09:13:42.149 08:00' }] }, { id: 3, clazz_id: 2, answers: [{ level: 3, created_at: '2022-01-19T09:13:42.149 08:00' }, { level: 8, created_at: '2022-02-19T09:13:42.149 08:00' }] }],
    result = Object
        .values(data.reduce((r, { clazz_id, answers }) => {
            r[clazz_id] ??= {};
            answers.forEach(({ level, created_at }) => {
                const 
                    months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
                    monthV = new Date(created_at).getMonth(),
                    month = months[monthV];

                r[clazz_id][monthV] ??= { clazz_id, level: 0, month };
                r[clazz_id][monthV].level  = level;
            });
            return r;
        }, {}))
        .map(Object.values);

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

  • Related