[Solved] How to create a new object from existing entries?


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 mapreduce 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?