How to calculate the accumulated values of a Json?

1

I have a json that returns an array with a date and measurements. Within the measures there are values that I want to consolidate, after ordering the data by month.

obj {
    0:{
      'timestamp': "2016-01-02T08:13:00+00:00",
      'measure':{
        'calories': {
          'text': 'cals',
          'unit': 10
        },
        'steps': {
          'text': 'm',
          'unit': 10
        }
      }
    },
    1:{
      'timestamp': "2016-01-03T08:13:00+00:00",
      'measure':{
        'calories': {
          'text': 'cals',
          'unit': 30
        },
        'steps': {
          'text': 'm',
          'unit': 30
        }
      }
    },
    3:{
      'timestamp': "2015-12-31T08:13:00+00:00",
      'measure':{
        'calories': {
          'text': 'cals',
          'unit': 15
        },
        'steps': {
          'text': 'm',
          'unit': 15
        }
      }
    },
    4:{
      'timestamp': "2015-12-31T08:13:00+00:00",
      'measure':{
        'calories': {
          'text': 'cals',
          'unit': 40
        },
        'steps': {
          'text': 'm',
          'unit': 40
        }
      }
    },
}

Basically this is the array with the objects that it returns to me, with momentJS I formatted the year and managed to filter by month, but I have not achieved any way to group and add the measure of each month, taking into account that every month has its days

expected result

  {
        'timestamp': '2016'
        'month': 'jan',
    'measure':{
            'calories': {
          'text': 'cals',
          'unit': 20 // valor consolidado de cada dia
        },
        'steps': {
          'text': 'm',
          'unit': 20 // valor consolidado de cada dia
        }
    },
    'timestamp': '2015'
        'month': 'dec',
    'measure':{
            'calories': {
          'text': 'cals',
          'unit': 20 // valor consolidado de cada dia
        },
        'steps': {
          'text': 'm',
          'unit': 20 // valor consolidado de cada dia
        }
    }

What methods could I use to solve it, I have tried with lodash but without achieving full results

    
asked by user2858993 20.05.2016 в 23:36
source

2 answers

2
  

Basically this is the array with the objects that it returns to me, with momentJS I formatted the year and managed to filter by month, but I have not achieved any way to group and add the measure of each month, taking into account that Every month has its days.

First of all, it is not an array, it is an object. An array of objects has the notation [ {}, {} ] and this object has the notation { 0: {}, 1: {} } .

Clarified this, here is an example that uses Object.keys and Array.reduce to obtain the sum of all the calories and the steps.

Basically Object.keys I use to get the key of the object ( [0,1,2,3] ) so I can treat it as if it were an array. (Eye! Maybe it would be better if you get it as an array directly from the server, if you can change it).

Then I use Array.reduce on that resulting array, to iterate over all the elements and get the accumulated value.

Since you have it solved, it will not be difficult to modify to put a filter by date and give it the exact format you need. Leave some comments in the snippet stack code that will help you do so.

Note: This does not require additional libraries since it is part of ES2015, but may require a polyfill to work on older browsers.

Object.keys(obj).reduce(function(prev, key) {

  prev.calories += obj[key].measure.calories.unit;
  prev.steps += obj[key].measure.steps.unit;

  return prev;   

}, { calories: 0, steps: 0 }); // <<-- valor inicial es prev

Keep in mind that if you want to use lodash or similar, the syntax would be very similar.

_.reduce(Object.keys(obj), function(prev, curr) { 
  // ... lo mismo
}, { calories: 0, steps: 0 });

var obj = {
  0: {
    'timestamp': "2016-01-02T08:13:00+00:00",
    'measure': {
      'calories': {
        'text': 'cals',
        'unit': 10
      },
      'steps': {
        'text': 'm',
        'unit': 10
      }
    }
  },
  1: {
    'timestamp': "2016-01-03T08:13:00+00:00",
    'measure': {
      'calories': {
        'text': 'cals',
        'unit': 30
      },
      'steps': {
        'text': 'm',
        'unit': 30
      }
    }
  },
  3: {
    'timestamp': "2015-12-31T08:13:00+00:00",
    'measure': {
      'calories': {
        'text': 'cals',
        'unit': 15
      },
      'steps': {
        'text': 'm',
        'unit': 15
      }
    }
  },
  4: {
    'timestamp': "2015-12-31T08:13:00+00:00",
    'measure': {
      'calories': {
        'text': 'cals',
        'unit': 40
      },
      'steps': {
        'text': 'm',
        'unit': 40
      }
    }
  },
};


function reduceWithoutFilter() {
       
  return Object.keys(obj).reduce(function(prev, key) {
    // esto dentro de un if y ya tienes un filtro, pero
    // quiza te conviene hacerlo en una etapa separada, es cuestión de diseño.
    prev.calories += obj[key].measure.calories.unit;
    prev.steps += obj[key].measure.steps.unit;
    return prev;   
  }, { calories: 0, steps: 0 }); // <<-- valor inicial es prev
  
}

console.log(reduceWithoutFilter());
    
answered by 21.05.2016 в 00:02
0

Here is an example of how to do it with moment and lodash.

I use moment to get the month and year of the date.

With the groupBy method of lodash I make a grouping by month.

With the lodash reduction method I make the sum of the units of each day.

Finally with the map method I return the new collection.

        var obj = {
            0: {
                'timestamp': "2016-01-02T08:13:00+00:00",
                'measure': {
                    'calories': {
                        'text': 'cals',
                        'unit': 10
                    },
                    'steps': {
                        'text': 'm',
                        'unit': 10
                    }
                }
            },
            1: {
                'timestamp': "2016-01-03T08:13:00+00:00",
                'measure': {
                    'calories': {
                        'text': 'cals',
                        'unit': 30
                    },
                    'steps': {
                        'text': 'm',
                        'unit': 30
                    }
                }
            },
            3: {
                'timestamp': "2015-12-31T08:13:00+00:00",
                'measure': {
                    'calories': {
                        'text': 'cals',
                        'unit': 15
                    },
                    'steps': {
                        'text': 'm',
                        'unit': 15
                    }
                }
            },
            4: {
                'timestamp': "2015-12-31T08:13:00+00:00",
                'measure': {
                    'calories': {
                        'text': 'cals',
                        'unit': 40
                    },
                    'steps': {
                        'text': 'm',
                        'unit': 40
                    }
                }
            }
        };

        var grouped = _.groupBy(obj,
            function(el) {
                var dat = moment(el.timestamp);
                return dat.year().toString() + '_' + dat.format('MMM');
            });
        var accum = _.map(grouped,
            function (measures, key) {
                return _.reduce(measures,
                    function(accumulator, el) {
                        accumulator.measure.calories.unit += el.measure.calories.unit;
                        accumulator.measure.steps.unit += el.measure.steps.unit;
                        return accumulator;
                    },
                    {
                        timestamp: key.split('_')[0],
                        month: key.split('_')[1],
                        measure: {
                            calories: { text: 'cals', unit: 0 },
                            steps: { text: 'm', unit: 0 }
                        }
                    });
            });

        console.log(accum);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.js"></script>
<script src="https://cdn.jsdelivr.net/lodash/4.12.0/lodash.min.js"></script>
    
answered by 21.05.2016 в 08:40