Reputation: 192
I want to groupBy my array of an object into some another desired array of objects. I go through several tutorials but didn't get the appropriate output.
What I want is based on their groupBy properties I want to group all the elements
Here is my input
permissions= [
{
code: 'U00',
permission_name: 'Read User',
groupBy: 'User',
icon: 'user',
},
{
code: 'U01',
permission_name: 'Create User',
groupBy: 'User',
icon: 'user',
},
{
code: 'B00',
permission_name: 'Read Batch',
groupBy: 'Batch',
icon: 'user',
},
{
code: 'B01',
permission_name: 'Create Batch',
groupBy: 'Batch',
icon: 'user',
},
{
code: 'B10',
permission_name: 'Update Batch',
groupBy: 'Batch',
icon: 'user',
},
];
Required output
Output = [
{
label: 'User',
icon: 'user',
children: [
{
label: 'Create Users',
},
{
label: 'Read All Users',
},
],
},
{
label: 'Batch',
children: [
{
label: 'Create Batchs',
},
{
label: 'Read All Batch',
},
{
label: 'Update Batch',
},
{
label: 'Disabled Batch',
},
],
},
];
Upvotes: 0
Views: 157
Reputation: 1035
[curItem.groupBy]You should try using reduce
: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
return Object.values(permissions.reduce((curObj, curItem) => {
if(!curObj.hasOwnProperty(curItem.groupBy)){
curObj[curItem.groupBy] = {
label: curItem.label,
icon: curItem.icon,
children: []
};
}
curObj[curItem.groupBy].children.push({ label: curItem.label });
return curObj;
}, {}));
Upvotes: 2
Reputation: 5603
You can use Array.prototype.reduce
to alter the permissions
Array the way you'll like.
let permissions = [{
code: 'U00',
permission_name: 'Read User',
groupBy: 'User',
icon: 'user',
},
{
code: 'U01',
permission_name: 'Create User',
groupBy: 'User',
icon: 'user',
},
{
code: 'B00',
permission_name: 'Read Batch',
groupBy: 'Batch',
icon: 'user',
},
{
code: 'B01',
permission_name: 'Create Batch',
groupBy: 'Batch',
icon: 'user',
},
{
code: 'B10',
permission_name: 'Update Batch',
groupBy: 'Batch',
icon: 'user',
}
];
let results = permissions.reduce(function(accumulator, current) {
let previousPermission = accumulator.find(function(el){
return el.label === current.groupBy
});
if(!previousPermission){
return accumulator.concat({
label: current.groupBy,
icon: current.icon,
children: [{
label: current.permission_name
}]
});
} else {
let permissionIndex = accumulator.findIndex(item => {
return item.label === previousPermission.label;
});
previousPermission = {
...previousPermission,
children: [
...previousPermission.children,
{ label: current.permission_name }
]
}
accumulator[permissionIndex] = previousPermission;
return accumulator;
}
}, []);
console.log(results);
Upvotes: 0
Reputation: 31
You could first create a function to reduce the array into an object, like so:
const groupBy = (prop, list) => {
return list.reduce((groups, item) => {
const propVal = item[prop];
const target = groups[propVal] ?? [];
return { ...groups, [propVal]: [...target, item] };
}, {});
};
Or shorter:
const groupBy = (prop, list) => list.reduce((groups, item) => ({ ...groups, [item[prop]]: [...groups[item[prop]] ?? [], item] }), {});
And then:
const permObj = groupBy('groiupBy', permissions);
// { User: [...], Batch: [...] }
Now you could just work with that object or continue by writing a second function:
const groupsToArray = (nameProp, groups) => Object.entries(groups).map((g) => ({ [nameProp]: g[0], data: g[1] }))
And use it:
const newPermList = groupsToArray('label', permObj);
which would leave you with an array of objects with the according labels and the children in the 'data' prop of each object.
Of course then you could still filter out or map to get rid of duplicate data that you dont need. But you get the idea.
Upvotes: 1
Reputation: 776
First step - get filtered necessary groupBy
values.
Second step - mapping through filtered groupBy
values and create a new array of objects based on your requirements.
const permissions = [
{
code: 'U00',
permission_name: 'Read User',
groupBy: 'User',
icon: 'user',
},
{
code: 'U01',
permission_name: 'Create User',
groupBy: 'User',
icon: 'user',
},
{
code: 'B00',
permission_name: 'Read Batch',
groupBy: 'Batch',
icon: 'user',
},
{
code: 'B01',
permission_name: 'Create Batch',
groupBy: 'Batch',
icon: 'user',
},
{
code: 'B10',
permission_name: 'Update Batch',
groupBy: 'Batch',
icon: 'user',
},
];
const groups = [ ...new Set(permissions.map(({ groupBy }) => groupBy)) ];
const result = groups.map(groupName => ({
value: permissions.find(permission => permission.groupBy === groupName).groupBy,
icon: permissions.find(permission => permission.icon === groupName.toLowerCase())?.icon,
children: permissions
.filter(permission => permission.groupBy === groupName)
.map(n => ({ value: n.permission_name })),
}));
const output = JSON.parse(JSON.stringify(result)); // For removing undefined keys.
console.log(output);
Upvotes: 0
Reputation: 11156
You colud find distinct groupBy
values and then iterate on this array to fill result array like:
let permissions= [
{
code: 'U00',
permission_name: 'Read User',
groupBy: 'User',
icon: 'user',
},
{
code: 'U01',
permission_name: 'Create User',
groupBy: 'User',
icon: 'user',
},
{
code: 'B00',
permission_name: 'Read Batch',
groupBy: 'Batch',
icon: 'user',
},
{
code: 'B01',
permission_name: 'Create Batch',
groupBy: 'Batch',
icon: 'user',
},
{
code: 'B10',
permission_name: 'Update Batch',
groupBy: 'Batch',
icon: 'user',
},
];
let groups = [...new Set(permissions.map(({groupBy})=>groupBy))];
let result = [];
for (let i = 0; i < groups.length; i++){
let res = {};
res.label = groups[i];
res.icon = permissions.filter(x => x.groupBy === groups[i])[0].icon;
res.children = [];
let arrayOfGroup = permissions.filter(x => x.groupBy === groups[i]);
for (let j = 0; j < arrayOfGroup.length; j ++){
let child = {};
child.label = arrayOfGroup[j].permission_name;
res.children.push(child);
}
result.push(res);
}
console.log(result);
Upvotes: 0
Reputation: 92
You can write something like:
const output = []
permissions.forEach(obj => {
const dest = output.find(target => target.label === obj.groupBy);
if (!dest) {
output.push({ label: obj.groupBy, icon: obj.icon, children: [ { label: obj.permission_name } ] })
} else {
dest.children.push({ label: obj.permission_name })
}
})
You are basically creating a new array, mapping the original based on your requires.
Upvotes: 1