Aim
Group tasks per employee/group of employees for which tasks were assigned to.
Data Context
- Each task can be assigned to more than one employee
- Each employee can have multiple tasks
- Values like employee
type
orname
are just extra data, meaning it's theemployee_id
that distinguishes them
Problem
Currently, I am able to group the tasks per employee, not group of employees. If a task is shared by more than one employee, it is repeated on the array, like the example tasks below (appear in 2 employees groups: for employee_id
111
and 999
if you run the last code snippet that has both the initial data and my current code).
{
"task_employee_id": 10001,
"task_name": "Maintenance",
"task_url": "www.task_url10001.com",
"status": "incomplete"
},
{
"task_employee_id": 20002,
"task_name": "Cleaning",
"task_url": "www.task_url20002.com",
"status": "completed"
},
Expected Result
I should have it like this
groupTasks: [
{
"employee_id": [{999},{111}]
"type": "ABC",
"name": "Lorem",
"tasks": [
{
"task_employee_id": 10001,
"task_name": "Maintenance",
"task_url": "www.task_url10001.com",
"status": "incomplete"
},
{
"task_employee_id": 20002,
"task_name": "Cleaning",
"task_url": "www.task_url20002.com",
"status": "completed"
}
]
},
{
"employee_id": 111,
"type": "ZHG",
"name": "Ipsum",
"tasks": [
{
"task_employee_id": 30003,
"task_name": "Fixing",
"task_url": "www.task_url30003.com",
"status": "incomplete"
}
]
},
{
"employee_id": 999,
"type": "ABC",
"name": "Lorem",
"tasks": [
{
"task_employee_id": 40004,
"task_name": "Checking",
"task_url": "www.task_url40004.com",
"status": "complete"
}
]
]
Sidenote: it could either be "employee_ids": [{"employee_id" :999},{"employee_id" : 111}]
or "employee_id": [999,111]
Here is the code snippet with the initial data and my current code that doesn't ouput the expected result
const data = [
{
task_id: 10001,
task_name: "Maintenance",
task_url: "www.task_url10001.com",
status: "incomplete",
employees: [
{ employee_id: 999, type: "ABC", name: "Lorem" },
{ employee_id: 111, type: "ZHG", name: "Ipsum" }
]
},
{
task_id: 20002,
task_name: "Cleaning",
task_url: "www.task_url20002.com",
status: "completed",
employees: [
{ employee_id: 111, type: "ZHG", name: "Ipsum" },
{ employee_id: 999, type: "ABC", name: "Lorem" }
]
},
{
task_id: 30003,
task_name: "Fixing",
task_url: "www.task_url30003.com",
status: "incomplete",
employees: [{ employee_id: 111, type: "ZHG", name: "Ipsum" }]
},
{
task_id: 40004,
task_name: "Checking",
task_url: "www.task_url40004.com",
status: "complete",
employees: [{ employee_id: 999, type: "ABC", name: "Lorem" }]
}
];
// current approach
const groupTasks = [
...data
.reduce(
(
groupTasksEmployees,
{
task_id: task_employee_id,
task_name,
task_url,
status,
employees = []
}
) => {
employees.forEach(({ employee_id, type, name }) => {
const employees = groupTasksEmployees.get(employee_id) ?? {
employee_id,
type,
name,
tasks: []
};
employees.tasks.push({
task_employee_id,
task_name,
task_url,
status
});
groupTasksEmployees.set(employee_id, employees);
});
return groupTasksEmployees;
},
new Map()
)
.values()
];
console.log("groupTasks: ", groupTasks);
CodePudding user response:
A possible solution, obtained by a slight modification of your code, could be:
const data = [
{
task_id: 10001,
task_name: "Maintenance",
task_url: "www.task_url10001.com",
status: "incomplete",
employees: [
{ employee_id: 999, type: "ABC", name: "Lorem" },
{ employee_id: 111, type: "ZHG", name: "Ipsum" }
]
},
{
task_id: 20002,
task_name: "Cleaning",
task_url: "www.task_url20002.com",
status: "completed",
employees: [
{ employee_id: 111, type: "ZHG", name: "Ipsum" },
{ employee_id: 999, type: "ABC", name: "Lorem" }
]
},
{
task_id: 30003,
task_name: "Fixing",
task_url: "www.task_url30003.com",
status: "incomplete",
employees: [{ employee_id: 111, type: "ZHG", name: "Ipsum" }]
},
{
task_id: 40004,
task_name: "Checking",
task_url: "www.task_url40004.com",
status: "complete",
employees: [{ employee_id: 999, type: "ABC", name: "Lorem" }]
}
];
// current approach
const groupTasks = [
...data
.reduce(
(
groupTasksEmployees,
{
task_id: task_employee_id,
task_name,
task_url,
status,
employees = []
}
) => {
let employee_ids = employees.map(o=>o.employee_id).sort();
const employee_ids_unique = employee_ids.join('_'),
type = employees[0]?.type,
name = employees[0]?.name;
if(employee_ids.length === 1){
employee_ids = employee_ids[0];
}
const employees_g = groupTasksEmployees.get(employee_ids_unique) ?? {
employee_id: employee_ids,
type,
name,
tasks: []
};
employees_g.tasks.push({
task_employee_id,
task_name,
task_url,
status
});
groupTasksEmployees.set(employee_ids_unique, employees_g);
return groupTasksEmployees;
},
new Map()
)
.values()
];
console.log("groupTasks: ", groupTasks);
This seems to produce your expected result, including the selection of only one name
and one type
in the aggregated data. It could easily be modified to include all employee name
s and type
s for each task that contains more than one employee.
CodePudding user response:
Make a key from all of the employee ids and use that to refer to the group in the reduce accumulator.
const output = data.reduce((acc, {employees, ...rest}) => {
const group = employees.map(e => e.employee_id).sort();
const key = group.join('_');
if(!acc[key]) {
acc[key] = {
id: group,
tasks: []
};
}
acc[key].tasks.push(rest);
return acc;
}, {});
const arr = Object.values(output);