const input = {
"item_name": "Drink",
"item_id": 1065,
"quantity_value": 1,
"item_price": 1,
"option": [
{
"max": 1,
"option": {
"min": 0,
"option_name": "Small",
"max": 1,
"price": 0,
"option_id": 3426,
"value": 1
},
"option_group_name": "Size",
"option_group_id": "drink_size",
"min": 1
},
{
"max": 1,
"option": {
"min": 0,
"option_name": "Medium",
"max": 1,
"price": 0,
"option_id": 3426,
"value": 1
},
"option_group_name": "Size",
"option_group_id": "drink_size",
"min": 1
},
{
"max": 1,
"option": {
"min": 0,
"option_name": "Large",
"max": 1,
"price": 0,
"option_id": 3426,
"value": 1
},
"option_group_name": "Size",
"option_group_id": "drink_size",
"min": 1
},
{
"max": 5,
"option": {
"min": 0,
"option_name": "Decaf",
"max": 1,
"price": 0,
"option_id": 3580,
"value": 1
},
"option_group_name": "Extras",
"option_group_id": "coffee_extras",
"min": 0
},
{
"max": 5,
"option": {
"min": 0,
"option_name": "Espresso Shot",
"max": 1,
"price": 30,
"option_id": 3581,
"value": 1
},
"option_group_name": "Extras",
"option_group_id": "coffee_extras",
"min": 0
}
]
};
// Accumulator for the outer max quantity. Assuming it's the sum of all the inner "max" quantities.
let maxQty = 0;
let _groupedOptions = [...new Set(input.option.map(o => o.option_group_id))].reduce((acc, next) => {
// Acquire the (outer) option for the [next] item, where next is the option_group_id.
const _filteredOptions = input.option.filter(o => o.option_group_id === next);
// Max qty of the following options. Assuming it's the sum of the inner quantities. Otherwise, change that.
let innerMaxQty = _filteredOptions.map(i => +i.max).reduce((a,b) => a + b, 0);
// Eventual update of the outer max quantity. Eventually change this if the calculation criteria is different.
maxQty = maxQty < innerMaxQty ? innerMaxQty : maxQty;
// Acquire the inner options of the looped item.
const _innerOptions = _filteredOptions.map(o => o.option);
// Push a new object containing the desired options in the inner option property, by getting the defualt object informations from the outer option group.
// As a side note, you should not get the _filteredOptions[0], but you should give further explanations about how the master object should calculated the properties, otherwise it's quite vague.
// After pushing, return the accumulator for the next iteration.
return acc.push(Object.assign(_filteredOptions[0], {
option: _innerOptions
})), acc;
}, []);
// Generate the output by cloning the input object, removing its `option` property, and assigning the calculated option_group property.
// I've also put maxQty, but I'm pretty sure you should give further explanations on how to calculate it, just change it as you need.
const output = Object.assign({}, input, {
quantity_max: maxQty,
option_group: _groupedOptions
});
delete output.option;
console.log(output);