Reputation: 59
thanks for all your help in my recent posts! This time I got an nested array and I want to group and count them. My array looks like this:
var arr = [
{
"account": {
"id": 123,
"name": "worker"
},
"fromCountry": "TE",
"status": "created"
},
{
"account": {
"id": 3,
"name": "worker"
},
"fromCountry": "TE",
"status": "pending"
},
{
"account": {
"id": 123,
"name": "worker"
},
"fromCountry": "TE",
"status": "created"
},
{
"account": {
"id": 1,
"name": "CEO"
},
"fromCountry": "FE",
"status": "done"
},
{
"account": {
"id": 1123,
"name": "worker"
},
"fromCountry": "FE",
"status": "created"
}
]
I want to group them by Country, count the countries and save in the child the name typs and count them as well. So it has to look like this:
[
{
name: "TE",
value: 3,
child: [
{
name: "worker",
count: 2
},
{
name: "CEO",
count: 1
}
]
},
{
name: "FE",
value: 2,
child: [
{
name: "worker",
count: 1
},
{
name: "CEO",
value: 1
}
]
}
]
(Note: I would not like to use extra javascript libraries)
Could you help me please?
Upvotes: 0
Views: 359
Reputation: 386680
The key question beside of the grouping is here, how to get a nested property. This grouping value is taken with a helper function which checks if the given key is an array or not. If an array, then take the items as keys for the object and return a possibly found value. Needless to say, it works for an arbitrary count of groups, depending on the data set.
function getGouped(array, groups) {
function getValue(object, key) {
return Array.isArray(key)
? key.reduce((o, k) => (o || {})[k], object)
: object[key];
}
var result = [],
object = { _: { children: result } };
array.forEach(function (o) {
groups.reduce(function (r, k) {
var name = getValue(o, k);
if (!r[name]) {
r[name] = { _: { name, count: 0 } };
r._.children = r._.children || [];
r._.children.push(r[name]._);
}
r[name]._.count++;
return r[name];
}, object);
});
return result;
}
var data = [{ account: { id: 123, name: "worker" }, fromCountry: "TE", status: "created" }, { account: { id: 3, name: "worker" }, fromCountry: "TE", status: "pending" }, { account: { id: 123, name: "worker" }, fromCountry: "TE", status: "created" }, { account: { id: 1, name: "CEO" }, fromCountry: "FE", status: "done" }, { account: { id: 1123, name: "worker" }, fromCountry: "FE", status: "created" }];
console.log(getGouped(data, ['fromCountry', ['account', 'name']]));
console.log(getGouped(data, ['fromCountry', ['account', 'name'], 'status']));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1
Reputation: 26844
You can use reduce
to group the arrays into an object. Use Object.values
to convert the object into an array. Loop thru the array using map
and form the child property into an array.
let arr = [{fromCountry:"TE",account:{name: "worker", id: 123},status:"created"},{fromCountry:"TE",account:{name: "worker", id: 3},status:"pending"},{fromCountry:"TE",account:{name: "worker", id: 123},status:"created"}, {fromCountry:"FE",account:{name: "CEO", id: 1},status:"done"}, {fromCountry:"FE",account:{name: "worker", id: 1123},status:"created"}];
let result = Object.values(arr.reduce((c, v) => {
let f = v.fromCountry;
c[f] = c[f] || {name: f,value: 0,child: {}};
c[f].child[v.account.id] = c[f].child[v.account.id] || {name: v.account.name,count: 0}
c[f].value++;
c[f].child[v.account.id].count++;
return c;
}, {})).map(o => {
o.child = Object.values(o.child);
return o;
});
console.log(result);
Upvotes: 1