An approach should consider breaking the OP’s entire task into two separate ones.
Within an intermediate step one firstly does reduce
the list of material items into a map of (grouped) material items.
The final step does a map
–reduce
on the values
of the intermediate result, where the reduce
task is responsible for summing up a material’s Code
specific Quantity
value …
function collectTotalCodeQuantity(index, item) {
const { Code, Quantity } = item;
// access or create the `Code` specific code quantity item.
const codeQuantityItem = (index[Code] ??= { Code, Quantity: 0 });
// sum up a `Code` specific code quantity item's quantity value.
codeQuantityItem.Quantity += Quantity;
return index;
}
function createMaterialGroup(index, item) {
const { Material: materialValue, ...rest } = item;
// create the `CodeQuantity` key in a more generic way from the
// `rest` object which is ... `item` data without `Material` property.
const compoundKey = Object.keys(rest).join('');
// access or create the `Material` specific group.
const group = index[materialValue] ??= { Material: materialValue };
// access or create the `CodeQuantity` specific list.
const list = group[compoundKey] ??= [];
// push the `rest` object into the `CodeQuantity` specific list.
list.push(rest);
return index;
}
const materialDataItemList = [{
"Material": "123",
"Code": "AAA",
"Quantity": 1
}, {
"Material": "123",
"Code": "BBB",
"Quantity": 2
}, {
"Material": "123",
"Code": "BBB",
"Quantity": 2
}, {
"Material": "456",
"Code": "AAA",
"Quantity": 7
}];
const totalCodeQuantityItemList = Object
.values(
materialDataItemList.reduce(createMaterialGroup, {})
)
.map(materialGroup => {
materialGroup.CodeQuantity = Object.values(
materialGroup.CodeQuantity.reduce(collectTotalCodeQuantity, {})
);
return materialGroup;
});
console.log({ totalCodeQuantityItemList });
console.log(
'... intermediate process result ... map of (grouped) material items ...',
materialDataItemList.reduce(createMaterialGroup, {})
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Edit
Moin! how can I add a new key “CodeQuantityGesamt” where the values of all “Quantity” of a “Material” is summed? example:
{ "Material": "123", "CodeQuantityGesamt": 5, "CodeQuantity": [{ "Code": "AAA", "Quantity": 1 }, { "Code": "BBB", "Quantity": 4 }] }
– InFlames82
This can be achieved by changing the mapping task from …
.map(materialGroup => {
materialGroup.CodeQuantity = Object.values(
materialGroup.CodeQuantity.reduce(collectTotalCodeQuantity, {})
);
return materialGroup;
});
… to e.g. …
.map(materialGroup => Object.assign(
materialGroup,
materialGroup.CodeQuantity.reduce(collectCodeQuantityTotals, {})
));
… together with adapting the implementation and changing the name of the former collectTotalCodeQuantity
reducer function which becomes collectCodeQuantityTotals
.
function collectCodeQuantityTotals(quantities, item, idx, arr) {
const { Code, Quantity } = item;
let {
CodeQuantityTotal = 0,
CodeQuantity = [],
index = {},
} = quantities;
// access ...
let codeQuantityItem = index[Code];
// ... or create the `Code` specific code quantity item.
if (!codeQuantityItem) {
codeQuantityItem = index[Code] = { Code, Quantity: 0 };
// push a newly created item into the CodeQuantity list.
CodeQuantity.push(codeQuantityItem);
}
// sum up a `Code` specific code quantity item's quantity value.
codeQuantityItem.Quantity += Quantity;
// sum up the total (or overall) code quantity value.
CodeQuantityTotal += Quantity;
// return a full collector/accumulator object as long as
// the reduce task takes place because `index` is needed
// as lookup, but return, as the final result, an object
// without the `index` property.
return (idx < arr.length - 1)
&& { CodeQuantityTotal, CodeQuantity, index }
|| { CodeQuantityTotal, CodeQuantity };
}
function createMaterialGroup(index, item) {
const { Material: materialValue, ...rest } = item;
// create the `CodeQuantity` key in a more generic way from the
// `rest` object which is ... `item` data without `Material` property.
const compoundKey = Object.keys(rest).join('');
// access or create the `Material` specific group.
const group = index[materialValue] ??= { Material: materialValue };
// access or create the `CodeQuantity` specific list.
const list = group[compoundKey] ??= [];
// push the `rest` object into the `CodeQuantity` specific list.
list.push(rest);
return index;
}
const materialDataItemList = [{
"Material": "123",
"Code": "AAA",
"Quantity": 1
}, {
"Material": "123",
"Code": "BBB",
"Quantity": 2
}, {
"Material": "123",
"Code": "BBB",
"Quantity": 2
}, {
"Material": "456",
"Code": "AAA",
"Quantity": 7
}];
const totalCodeQuantityItemList = Object
.values(
materialDataItemList.reduce(createMaterialGroup, {})
)
.map(materialGroup => Object.assign(
materialGroup,
materialGroup.CodeQuantity.reduce(collectCodeQuantityTotals, {})
));
console.log({ totalCodeQuantityItemList });
console.log(
'... intermediate process result ... map of (grouped) material items ...',
materialDataItemList.reduce(createMaterialGroup, {})
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
2
solved How to create a new object from existing entries?