Nodejs: Object aggregation
Solution 1:
Well I guess you can make it more dynamic(something to group by an unknown amount of attributes)
First, I give you the answer in your output format in structure[{values:[...objectsInGroup],...groupingInfo}, ...otherGroupObjects]
const myList=[{"attr_id":1,"type":"color","value_index":10,"value_label":"Blue"},{"attr_id":1,"type":"color","value_index":15,"value_label":"Red"},{"attr_id":2,"type":"size","value_index":10,"value_label":"Small"},{"attr_id":2,"type":"size","value_index":14,"value_label":"Big"}]
function groupList(list,attributes){
var cache={} //for finding elements that have the same attributes
for(let item of list){
let ID=attributes.map(attr=>item[attr]).join('-')
//items with same ID would be grouped together
cache[ID]? cache[ID].values.push(item): cache[ID]={values:[item]}
//if ID exists.. add to the group, else make the group
attributes.forEach(key=>{
if(!cache[ID][key]){ cache[ID][key]=item[key] }
})
}
return Object.values(cache)
}
const newList=groupList(myList,['attr_id','type'])
console.log(newList)
But what if there was a values
attribute that is in the original item
s in the list
that you wanted it sorted by? only one value can exist per key.. in that case you can change the structure to[{values:[...objectsInGroup],info:{...groupingInfo}} ...otherGroupObjects]
const myList=[{"attr_id":1,"type":"color","value_index":10,"value_label":"Blue"},{"attr_id":1,"type":"color","value_index":15,"value_label":"Red"},{"attr_id":2,"type":"size","value_index":10,"value_label":"Small"},{"attr_id":2,"type":"size","value_index":14,"value_label":"Big"}]
function groupList(list,attributes){
var cache={} //for finding elements that have the same attributes
for(let item of list){
let ID=attributes.map(attr=>item[attr]).join('-')
//items with same ID would be grouped together
cache[ID]? cache[ID].values.push(item): cache[ID]={values:[item]}
//if ID exists.. add to the group, else make the group
if(!cache[ID].info){
cache[ID].info={} //info about the grouping of this array
attributes.forEach(key=>cache[ID].info[key]=item[key])
}
}
return Object.values(cache)
}
const newList=groupList(myList,['attr_id','type'])
console.log(newList)
Solution 2:
Im not necessarily sure if this is any better, but this is how I would maybe go about this. You could easily wrap this into a function
const finalObjects = [];
const checkIdInArray = (id) => finalObjects.find((obj) => obj.attr_id === id);
normalizedList.forEach((element) => {
if (!checkIdInArray(element.attr_id)) {
// Then add to array as its not been added yet
finalObjects.push({
attr_id: element.attr_id,
type: element.type,
values: [
{
index: element.value_index,
label: element.value_label,
},
],
});
return;
}
// Get the index of the existing id
const arrIndex = finalObjects.findIndex((e) => e.attr_id === element.attr_id);
finalObjects[arrIndex].values.push({
index: element.value_index,
label: element.value_label,
});
});
console.log(JSON.stringify(finalObjects));