Search code examples
javascriptnode.jsmomentjslodash

Group and sum time series data with LoDash


I want to group this data by ISO week and sum up the registrations. How can I do this with LoDash? My latest solution and sample data looks like this:

const registrationJson = [ 
  { date: 2018-02-19T00:00:00.000Z, registrations: '7' },
  { date: 2018-02-20T00:00:00.000Z, registrations: '1' },
  { date: 2018-02-21T00:00:00.000Z, registrations: '3' },
  { date: 2018-02-22T00:00:00.000Z, registrations: '4' },
  { date: 2018-02-23T00:00:00.000Z, registrations: '1' },
  { date: 2018-02-28T00:00:00.000Z, registrations: '3' },
  { date: 2018-03-08T00:00:00.000Z, registrations: '1' } ]

const groupedResults = _(registrationJson)
  .groupBy("date")
  .map(item => {
    return {
      date: moment(item["date"])
        .startOf("isoWeek")
        .toString(),
      registrations: _.sumBy(item, "registrations")
    }
  })
  .value()

This however returns to wrong output:

[ { date: 'Mon Mar 12 2018 00:00:00 GMT+0100',
    registrations: '7' },
  { date: 'Mon Mar 12 2018 00:00:00 GMT+0100',
    registrations: '1' },
  { date: 'Mon Mar 12 2018 00:00:00 GMT+0100',
    registrations: '3' },
  { date: 'Mon Mar 12 2018 00:00:00 GMT+0100',
    registrations: '4' },
  { date: 'Mon Mar 12 2018 00:00:00 GMT+0100',
    registrations: '1' },
  { date: 'Mon Mar 12 2018 00:00:00 GMT+0100',
    registrations: '3' },
  { date: 'Mon Mar 12 2018 00:00:00 GMT+0100',
    registrations: '1' } ]

Solution

  • Your code's current version works next way: first group by date(not by week!) and then transforming elements with map. And since each date is unique in that list your grouping is useless. Do it in reverse order:

    const registrationJson = [ 
          { date: 2018-02-19T00:00:00.000Z, registrations: '7' },
          { date: 2018-02-20T00:00:00.000Z, registrations: '1' },
          { date: 2018-02-21T00:00:00.000Z, registrations: '3' },
          { date: 2018-02-22T00:00:00.000Z, registrations: '4' },
          { date: 2018-02-23T00:00:00.000Z, registrations: '1' },
          { date: 2018-02-28T00:00:00.000Z, registrations: '3' },
          { date: 2018-03-08T00:00:00.000Z, registrations: '1' } ]
    
    const groupedResults = _(registrationJson)
          .map(item => {
              return {
                  date: moment(item["date"])
                        .startOf("isoWeek")
                        .toString(),
                   registrations: parseInt(item.registrations)
              }
          })
          .groupBy("date")
          .mapValues(item => {
               /* 
                here for each isoWeek start as a key you will get 
                list of elements for the same week; item is an array
               */
               return _.sumBy(item, 'registrations');
           })
          .value()
    

    Also be aware of data type. Since your registrations was a string it could result to concatenation instead of summing up.