Count values of json object

Hi,

I would like to count a value of json objects. For instance:

var requests = [ 
  {
        "id": "1",
        "firstname": "John",
        "lastname": "Doe",
        "allowance": "56",
        "employeeid": "1",
        "type": "Ilness",
        "hours":"8"
    },
      {
        "id": "2",
        "firstname": "John",
        "lastname": "Doe",
        "allowance": "56",
        "employeeid": "1",
        "type": "Holiday",
        "hours":"8"
    } 
      {
        "id": "3",
        "firstname": "John",
        "lastname": "Doe",
        "allowance": "56",
        "employeeid": "1",
        "type": "Holiday",
        "hours":"8"
    }     
    ];

The result I need:

Illness: 8 hours
Holiday 16 hours

Thanks in advance,

Jan

This is a very alternative solution that doesn’t involve coding. You could simply paste the JSON into json-csv.com which will produce a CSV file. Open the CSV file up in Excel and then you can group and sum the appropriate data.

I’m sorry if I wasn’t clear on this… But I would like to use it in my Ionic project.

How’s this - a simple way?
Or were you looking for something more complex?

(BTW, the requests array had some typos).

var requests = [ 
  {
        "id": "1",
        "firstname": "John",
        "lastname": "Doe",
        "allowance": "56",
        "employeeid": "1",
        "type": "Illness",
        "hours":"8"
    },
      {
        "id": "2",
        "firstname": "John",
        "lastname": "Doe",
        "allowance": "56",
        "employeeid": "1",
        "type": "Holiday",
        "hours":"8"
    }, 
      {
        "id": "3",
        "firstname": "John",
        "lastname": "Doe",
        "allowance": "56",
        "employeeid": "1",
        "type": "Holiday",
        "hours":"8"
    }     
    ];


var sumByKey = function(array, keyField, keyValue, valueField){
  var sum = 0;
  for(var i=0, len=array.length; i<len; i++)
    if(array[i][keyField] == keyValue)
      sum += parseFloat(array[i][valueField])
	return sum;
}

console.log(sumByKey(requests, "type", "Holiday", "hours"));
console.log(sumByKey(requests, "type", "Illness", "hours"));
1 Like

I use https://lodash.com/

//declare in index.html

You can do it inn your code:

_(requests).filter({‘type’:‘Ilness’}).pluck(‘hours’).reduce(function(sum,el){return sum+el},0) //result 08

_(requests).filter({‘type’:‘Holiday’}).pluck(‘hours’).reduce(function(sum,el){return sum+el},0) //result 088

2 Likes

Thanks! This works great!
I added another parameter to check which user is currently in the $param.employeeId, like this:

$scope.myId = $stateParams.employeeId;
    	
var sumByKey = function(array, keyField, keyValue, valueField, keyFieldEmp, keyValueEmp){
    	var sum = 0;
    	for(var i=0, len=array.length; i<len; i++)
        	if(array[i][keyField] == keyValue && array[i][keyFieldEmp] == keyValueEmp)
        		sum += parseFloat(array[i][valueField])
        	return sum;
    }
    	console.log(sumByKey($scope.reportrequests, "type", "Illness", "hours", "employeeid", $scope.myId));

But now… I have to search for each type (Illness, Holiday etc.). So, for instance, if a new request is made called “Time-off”, I should make a new row.

Is it possible to check which types there are and list each type with the hours.

Thanks!

Sorry, if this is a bit old school, but I really like Arrays for this kind of tasks…

  var requests = [ 
      {
            "id": "1",
            "firstname": "John",
            "lastname": "Doe",
            "allowance": "56",
            "employeeid": "1",
            "type": "Illness",
            "hours":"8"
        },
          {
            "id": "2",
            "firstname": "John",
            "lastname": "Doe",
            "allowance": "56",
            "employeeid": "1",
            "type": "Holiday",
            "hours":"8"
        }, 
          {
            "id": "3",
            "firstname": "John",
            "lastname": "Doe",
            "allowance": "56",
            "employeeid": "1",
            "type": "Holiday",
            "hours":"8"
        }     
        ];
    
    /**
     * Enumerate all key values based on groupBy key name
     * @param {Array} array An array of objects to use
     * @param {String} groypBy Name of the key to use for grouping
     * @returns {Array} An array of all unique values found for the key
     */
    var getKeys = function(array, groupBy){
      // list all keys
      var keys = [];
      for(var i=0, len=array.length; i<len; i++)
        if(keys.indexOf(array[i][groupBy]) == -1)
          keys.push(array[i][groupBy]);
      return keys;
    }
    
    /**
     * Calc the sum of the values of a key in an array of objects
     * @param {Array} array An array of objects to use
     * @param {String} keyField Name of the key to use for grouping
     * @param {String} keyValue Filter only objects with this value
     * @param {String} valueField The key name of the thing to calc sum of
     * @returns {Number} Sum
     */
    var sumByKey = function(array, keyField, keyValue, valueField){
      var sum = 0;
      for(var i=0, len=array.length; i<len; i++)
        if(array[i][keyField] == keyValue)
          sum += parseFloat(array[i][valueField])
    	return sum;
    }
    
    
    
    // Now, just use the getKeys to enumerate all unique keys,
    // then call sumByKey for each.
    // Just an example; you could construct a 2D array of the results:

    var keys = getKeys(requests, "type");
    var rows = [];
    for(var i=0, len=keys.length; i<len; i++)
      rows.push([keys[i], sumByKey(requests, "type", keys[i], "hours")]);
    
    console.log(rows);

    // [['Illness', 8], ['Holiday', 16]]

console.log(rows) return this:

	<div class="list">
	  <ion-item class="item" ng-repeat="row in rows">
		<p>{{row.0}}</p>
		<h2>{{row.1}}</h2>
	  </ion-item>
	</div>

Nothing happens when i put that code in my HTML?

Did you add $scope.rows = rows ?

Then,
row in rows as you did and
{{row[0]}} should be "Illness"
and {{row[1]}} = 8.

Works like a charm, great! But now my json output changed a bit, like this:

{
    "1": {
        "employeeid": "1",
        "firstname": "Steve",
        "lastname": "Jobs",
        "role": "Director",
        "requests": [
            {
                "id": "1",
                "startdate": "2014-11-12",
                "enddate": "2014-11-12",
                "type": "Ilness",
                "hours": "6",
                "reason": "My back hurts"
            },
            {
                "id": "2",
                "startdate": "2014-11-21",
                "enddate": "2014-11-21",
                "type": "Holiday",
                "hours": "8",
                "reason": "holiday reason"
            }
        ]
    },
    "2": {
        "employeeid": "2",
        "firstname": "John",
        "lastname": "Doe",
        "role": "Employee",
        "requests": [
            {
                "id": "3",
                "startdate": "2014-11-12",
                "enddate": "2014-11-12",
                "type": "Time-off",
                "hours": "8",
                "reason": "Just, because"
            },
            {
                "id": "4",
                "startdate": "2014-11-27",
                "enddate": "2014-11-27",
                "type": "Ilness",
                "hours": "8",
                "reason": "test"
            }
        ]
    },
    "3": {
        "employeeid": "3",
        "firstname": "Test",
        "lastname": "Test",
        "role": "Employee",
        "requests": [
            {
                "id": "5",
                "startdate": "2014-11-27",
                "enddate": "2014-11-27",
                "type": "Training",
                "hours": "9",
                "reason": "Software engineering training"
            }
        ]
    }
}

See, I made an array in an array where each parent-array starts with the employee id. I would like to check which employee is selected, this works (stored in variable employeeId)… And display the types of requests with hours (like before) depending on the user which is selected.

Thanks in advance!

You could easily just pick the requests array from the object and use that.
Many ways to do it, an example below. Having read all the json to an object called data, then:

var employeeId = 2;
var requests = data[employeeId].requests;
console.log(requests);

BTW, data[employeeId].requests works since you can write object.propertyName alternatively object[propertyName]. Handy especially when json-files have tricky names not suitable for javascript variables (like “album-name” - you can not call playlists.album-name, but playlists[“album-name”] is OK.)
Now you can use that requests Array to calc sums.

Perfect! thanks.

Final thing… I’ve got a total allowance, which is for instance 80 hours and stored in $scope.totalallowance. I would like to calculate the remaining hours. So, $scope.totalallowance - all types.

Thanks :smile:

var sumAll = function(array, valueField){
    var sum = 0;
    for(var i=0, len=array.length; i<len; i++)
        sum += parseFloat(array[i][valueField])
    return sum;
}

Feed the requests of a person to that, and valueField is “hours”.

var employeeId = 2;
var requests = data[employeeId].requests;
$scope.remaining = $scope.totalallowance - sumAll(requests, "hours");
1 Like

Thanks a million times :smiley:

Just to get back on this code one more time… It’s working perfect when I actually have one or more of the values, but when there isn’t one of them, the loop doesn’t stop and the view freezes.

Can you help me please?

Hmm… Should work like that / sum=0 first, the for-loop should not run at all if the array is an empty array.
Check an empty “requests” element in the json file - add

console.log(array);

to the beginning of the sumAll function and check console in the browser. It probably is already throwing an error for not being possible to call .length on the non-array thing.

If the json has [ ] as a value for the empty requests – it is an empty array and all OK. But if it is not an array at all ( " " or null or something like that), you should add a sanity check to the sumAll function:
Best bet would be using Angular .isArray() for that.
https://docs.angularjs.org/api/ng/function/angular.isArray

var sumAll = function(array, valueField){
    var sum = 0;
    if(angular.isArray(array))
        for(var i=0, len=array.length; i<len; i++)
            sum += parseFloat(array[i][valueField]);
    return sum;
}

Exactly! The array returned null, could solve this with .isArray()