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

[ad_1]

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

[ad_2]

solved How to create a new object from existing entries?