This is a bit tricky to find the right words, so hopefully showing some code will help.
I have the following (simplified) array of people and their departments. This comes from CMS data which allows a person to be added to multiple departments (hence why departments
is an array).
[
{
id: '12345',
name: 'Person 1',
jobTitle: 'Engineering director',
departments: ['Engineering', 'Leadership']
},
{
id: '54321',
name: 'Person 2',
jobTitle: 'Junior engineer',
departments: ['Engineering']
},
{
id: '00001',
name: 'Person 3',
jobTitle: 'Founder',
departments: ['Leadership']
},
{
id: '00099',
name: 'Person 4',
jobTitle: 'No department',
departments: []
}
]
The result I'm after is to get the unique values of departments
and create arrays for each, with the appropriate users inside it, so something like:
{
'Engineering': [
{
id: '12345',
name: 'Person 1',
jobTitle: 'Engineering director',
departments: ['Engineering', 'Leadership']
},
{
id: '54321',
name: 'Person 2',
jobTitle: 'Junior engineer',
departments: ['Engineering']
}
],
'Leadership': [
{
id: '12345',
name: 'Person 1',
jobTitle: 'Engineering director',
departments: ['Engineering', 'Leadership']
},
{
id: '00001',
name: 'Person 3',
jobTitle: 'Founder',
departments: ['Leadership']
}
]
}
I've got a groupBy
function in my code already, but it doesn't quite do what I want (because it's not expecting an array as the property value), so if a person
has multiple departments, I get an array with a concatenated name of both departments, but I want the same person
to appear in multiple arrays instead.
This is my current groupBy
function, but it's now distracting me and reduce
is a concept my brain just really struggles with...!
function groupBy(objectArray, property) {
return objectArray.reduce(function (acc, obj) {
var key = obj[property];
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(obj);
return acc;
}, {});
}
// which I can use like:
const groupedPeople = Object.entries(groupBy(people, "departments"));
// and it'll return
/*
{
'Engineering,Leadership': [
{
id: '12345',
name: 'Person 1',
jobTitle: 'Engineering director',
departments: ['Engineering', 'Leadership']
}
],
'Engineering': [
{
id: '54321',
name: 'Person 2',
jobTitle: 'Junior engineer',
departments: ['Engineering']
}
],
'Leadership': [
{
id: '00001',
name: 'Person 3',
jobTitle: 'Founder',
departments: ['Leadership']
}
]
}
*/
I feel like I'm close, but can't get my brain to engage!
const people = [{
id: '12345',
name: 'Person 1',
jobTitle: 'Engineering director',
departments: ['Engineering', 'Leadership']
},
{
id: '54321',
name: 'Person 2',
jobTitle: 'Junior engineer',
departments: ['Engineering']
},
{
id: '00001',
name: 'Person 3',
jobTitle: 'Founder',
departments: ['Leadership']
},
{
id: '00099',
name: 'Person 4',
jobTitle: 'No department',
departments: []
}
]
function groupBy(objectArray, property) {
return objectArray.reduce(function(acc, obj) {
var key = obj[property];
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(obj);
return acc;
}, {});
}
// which I can use like:
const groupedPeople = Object.entries(groupBy(people, "departments"));
console.log("Grouped:", groupedPeople);
var key = obj[property];
on this line in your code, the key
variable represents the array of deparments
, which you then use as acc[key]
. What JS does it that in converts the array into string to be used as a key of the acc
object and the process for that is to just join the array by commas. What you need is to loop over the array instead:
function groupBy(objectArray, property) {
return objectArray.reduce(function (acc, obj) {
var keys = obj[property];
keys.forEach(key => {
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(obj);
})
return acc;
}, {});
}
Such change will make it work for your use case, the groupBy
function will no longer work if the key is not an array, so use with caution or make it support both strings and arrays.