When processing data, it is very useful to be able to group by variables and calculate statistics for each group. In Javascript, we can use the reduce function to help us build a group by function.
Grouping Objects by Multiple Properties in Array in Javascript
Let’s say we have data such as the following:
var array = [
{thing: 'ball', color: 'red', size: 'big', value: 10},
{thing: 'bat', color: 'blue', size: 'small', value: 15},
{thing: 'bat', color: 'red', size: 'small', value: 11}
{thing: 'bat', color: 'red', size: 'small', value: 21},
{thing: 'bat', color: 'red', size: 'big', value: 13},
{thing: 'helmet', color: 'blue', size: 'medium', value: 30},
{thing: 'helmet', color: 'red', size: 'medium', value: 13},
{thing: 'helmet', color: 'blue', size: 'big', value: 30},
{thing: 'bat', color: 'blue', size: 'medium', value: 14},
{thing: 'ball', color: 'red', size: 'medium', value: 13},
{thing: 'ball', color: 'blue', size: 'small', value: 8}
];
It would be very useful if we could group by the different properties and then sum the values to get the sum of the different groups.
Basically, what we want, is to be able to get the following:
[ { thing: 'ball', value: 31 },
{ thing: 'bat', value: 74 },
{ thing: 'helmet', value: 73 } ]
There are many snippets on how to reduce data and group by one property, but I want to show you how to do it with multiple properties.
The following function gives you the ability to group an array by multiple properties:
function GroupBy(array, keys, variable) {
var i, key, temp, split;
var data = array.reduce((result,currentValue) => {
key = "";
for(i = 0; i < keys.length; i++) {
key = key + currentValue[keys[i]] + "_";
}
if(!result[key]) {
result[key] = 0;
}
result[key] += parseFloat(currentValue[variable]);
return result;
}, {});
var grouped = [];
Object.keys(data).forEach(function(key) {
temp = {};
split = key.split("_");
for(i=0; i < split.length - 1; i++) {
temp[keys[i]] = split[i]
}
temp[variable] = data[key];
grouped.push(temp);
});
return grouped;
}
Below, you can see how running the function with different inputs will give us the desired group sums.
// GroupBy(array,[],"value"):
[ { value: 178 } ]
// GroupBy(array,["thing"],"value")
[ { thing: 'ball', value: 31 },
{ thing: 'bat', value: 74 },
{ thing: 'helmet', value: 73 } ]
// GroupBy(array,["thing","color"],"value"):
[ { thing: 'ball', color: 'red', value: 23 },
{ thing: 'bat', color: 'blue', value: 29 },
{ thing: 'bat', color: 'red', value: 45 },
{ thing: 'helmet', color: 'blue', value: 60 },
{ thing: 'helmet', color: 'red', value: 13 },
{ thing: 'ball', color: 'blue', value: 8 } ]
// GroupBy(array,["thing","color","size"],"value"):
[ { thing: 'ball', color: 'red', size: 'big', value: 10 },
{ thing: 'bat', color: 'blue', size: 'small', value: 15 },
{ thing: 'bat', color: 'red', size: 'small', value: 32 },
{ thing: 'bat', color: 'red', size: 'big', value: 13 },
{ thing: 'helmet', color: 'blue', size: 'medium', value: 30 },
{ thing: 'helmet', color: 'red', size: 'medium', value: 13 },
{ thing: 'helmet', color: 'blue', size: 'big', value: 30 },
{ thing: 'bat', color: 'blue', size: 'medium', value: 14 },
{ thing: 'ball', color: 'red', size: 'medium', value: 13 },
{ thing: 'ball', color: 'blue', size: 'small', value: 8 }]
// GroupBy(array,["size","color","thing"],"value"):
[ { size: 'big', color: 'red', thing: 'ball', value: 10 },
{ size: 'small', color: 'blue', thing: 'bat', value: 15 },
{ size: 'small', color: 'red', thing: 'bat', value: 32 },
{ size: 'big', color: 'red', thing: 'bat', value: 13 },
{ size: 'medium', color: 'blue', thing: 'helmet', value: 30 },
{ size: 'medium', color: 'red', thing: 'helmet', value: 13 },
{ size: 'big', color: 'blue', thing: 'helmet', value: 30 },
{ size: 'medium', color: 'blue', thing: 'bat', value: 14 },
{ size: 'medium', color: 'red', thing: 'ball', value: 13 },
{ size: 'small', color: 'blue', thing: 'ball', value: 8 }]
If you need a different aggregation, you would change the following line:
result[key] += parseFloat(currentValue[variable]);
For example, if you wanted to find the count of each object, you would replace it with:
result[key] += 1;
Finding the minimum and maximum are easy as well, but you have to be careful with how you initialize the property.
Hopefully this article has been useful for you to learn how to aggregate a JavaScript array of objects.
Hello,
Thank you for your hard working.
So, I that the following code need to be update for correction.
Before:
temp[variable] = array[key];
After
temp[variable] = data[key];
—–
Yes, you are right, thank you.
How do you group if the property you are wanting to group by is nested like so? I want to group my vendor id first then those grouped by vendor need to be grouped by category name.
[
{id: ‘cl93pfpgi21004uwudny1nu31s’, quantity: ‘213.00’, product: {
category: {
name: “flower”
}},
vendor: {
id: “8dsjdus98ew8”,
name: “Amazon”
}
}}
{id: ‘cl981dgur17145ioudevs3lc0a’, quantity: ‘9.76’, product: {
category: {
name: “flower”
}},
vendor: {
id: “auisd94j323jk”,
name: “Big Ben”
}
}}
{id: ‘cl981ptxc22223ioudj3m9iwda’, quantity: ‘3.67’, product: {
category: {
name: “concentrate”
},
vendor: {
id: “2mdufs78s8d”,
name: “Big Ben”
}
}}
]
Without having to modify the function in the article, you could “flatten” your structure and create variables like “product_category_name”, “vendor_id” and “vendor_name”. Then after this preprocessing step, you could group by those variables and then get the result back into the original structure.
Otherwise, something like this could work.