Home > Back-end >  Group by property of an object within a nested array
Group by property of an object within a nested array

Time:12-18

How would you group an array by a property of the objects in a nested array. Either vanilla or lodash.

For example, how would you group an array of tasks by the assignee, when tasks can have more than one person assigned.

Example data:

[
  {
    "assignees": [
      {
        "name": "John",
        "uid": "id0001"
      },
      {
        "name": "Sally",
        "uid": "id0002"
      }
    ],
    "title": "Task 1",
    "status": "To do"
  },
  {
    "assignees": [
      {
        "name": "John",
        "uid": "id0001"
      }
    ],
    "title": "Task 2",
    "status": "To do"
  },
  {
    "assignees": [
      {
        "name": "Sally",
        "uid": "id0002"
      }
    ],
    "title": "Task 3",
    "status": "To do"
  }
]

Example desired result:


  {
    "id0001": {
      "name": "John",
      "tasks": [
        {
          "title": "Task 1",
          "status": "To do"
        },
        {
          "title": "Task 2",
          "status": "To do"
        }
      ]
    }
  },
  {
    "id0002": {
      "name": "Sally",
      "tasks": [
        {
          "title": "Task 1",
          "status": "To do"
        },
        {
          "title": "Task 3",
          "status": "To do"
        }
      ]
    }
  }

I have a lot of things both vanilla and lodash - a simple example is below. I was expecting an array of three groups. One for Sally, one for John and one for Sally and John:

  const grouped = _.groupBy(taskList, (task) => task.assignees);

But that returns one group [object Object] with all the tasks in it.

CodePudding user response:

Since uids are unique, the Array seems like an overhead. I suggest to get an Object literal with the tasks grouped by the user's uids: like:

{
  id0001: {...user, tasks: []},
  id0002: {...user, tasks: []},
}

Example:

const groupTasksByUserId = (arr) => arr.reduce((ob, {assignees, ...task}) => {
  assignees?.forEach((user) => {
    ob[user.uid] ??= {...user, tasks: []};
    ob[user.uid].tasks.push(task)
  });
  return ob;
}, {});

const data = [{
  "assignees": [{"name": "John", "uid": "id0001"}, {"name": "Sally","uid": "id0002"}],
  "title": "Task 1",
  "status": "To do"
}, {
  "assignees": [{"name": "John", "uid": "id0001"}],
  "title": "Task 2",
  "status": "To do"
}, {
  "assignees": [{"name": "Sally", "uid": "id0002"}],
  "title": "Task 3",
  "status": "To do"
}];

const res = groupTasksByUserId(data);
// console.log(res);
console.log(JSON.stringify(res, 0, 2));

Find out more about the above used Array methods (reduce and forEach) on MDN Docs

  • Related