frosty4321
frosty4321

Reputation: 59

group, filter and count in nested array

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

Answers (2)

Nina Scholz
Nina Scholz

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

Eddie
Eddie

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

Related Questions