Search code examples
javascriptarraysjavascript-objectsreduce

Merge objects in array based on one key using reduce


I have array of objects:

[{sku: "BS-WHITE-1", GB: 15, total: 0, inbound: 0, available: 0, …},
{sku: "BS-WHITE-1", DE: 4},
{sku: "BS-WHITE-1", ES: 0},
{sku: "BS-WHITE-1", IT: 3},
{sku: "BS-WHITE-1", FR: 0},
{sku: "BS-WHITE-2", GB: 19, total: 40, inbound: 0, available: 40, …}
{sku: "BS-WHITE-2", DE: 2},
{sku: "BS-WHITE-2", FR: 5},
{sku: "BS-WHITE-2", ES: 3},
{sku: "BS-WHITE-2", IT: 6},
{sku: "BS-WHITE-3", GB: 21, total: 51, inbound: 1, available: 50, …}
{sku: "BS-WHITE-3", DE: 1},
{sku: "BS-WHITE-3", ES: 1},
{sku: "BS-WHITE-3", IT: 2},
{sku: "BS-WHITE-3", FR: 2},
{sku: "BS-WHITE-4", GB: 43, total: 42, inbound: 8, available: 31, …},
{sku: "BS-WHITE-4", DE: 8},
{sku: "BS-WHITE-4", FR: 7},
{sku: "BS-WHITE-4", ES: 3},
{sku: "BS-WHITE-4", IT: 17}]

And I want to merge objects based on key "sku" to get

[{sku: "BS-WHITE-1", GB: 15, DE: 4,ES: 0,IT: 3, FR: 0, total: 0, …},
{sku: "BS-WHITE-2", GB: 19, DE: 2,ES: 3,IT:6, FR: 5, total: 0, …},
{sku: "BS-WHITE-3", GB: 21, DE: 1,ES: 1,IT:2, FR: 2, total: 0, …},
{sku: "BS-WHITE-4", GB: 43, DE: 8,ES: 3,IT:17, FR: 7, total: 0, …}]

to do it I use reduce

const out = map.reduce((a, v) => {
  if (a[v.sku]) {
    a[v.sku].GB = a[v.sku].GB; //ok
    a[v.sku].DE = (v.DE) ? v.DE : 222; //?
    a[v.sku].FR = a[v.sku].FR ? a[v.sku].FR : 555; //?
    a[v.sku].IT = 2; //
    a[v.sku].ES = a[v.sku].ES; //?
  } else {
    a[v.sku] = v;
  }
  return a;
}, {});
console.log(Object.values(out));
<script>
const map = [{sku: "BS-WHITE-1", GB: 15, total: 0, inbound: 0, available: 0 },
    {sku: "BS-WHITE-1", DE: 4},
    {sku: "BS-WHITE-1", ES: 0},
    {sku: "BS-WHITE-1", IT: 3},
    {sku: "BS-WHITE-1", FR: 0},
    {sku: "BS-WHITE-2", GB: 19, total: 40, inbound: 0, available: 40},
    {sku: "BS-WHITE-2", DE: 2},
    {sku: "BS-WHITE-2", FR: 5},
    {sku: "BS-WHITE-2", ES: 3},
    {sku: "BS-WHITE-2", IT: 6},
    {sku: "BS-WHITE-3", GB: 21, total: 51, inbound: 1, available: 50},
    {sku: "BS-WHITE-3", DE: 1},
    {sku: "BS-WHITE-3", ES: 1},
    {sku: "BS-WHITE-3", IT: 2},
    {sku: "BS-WHITE-3", FR: 2},
    {sku: "BS-WHITE-4", GB: 43, total: 42, inbound: 8, available: 31},
    {sku: "BS-WHITE-4", DE: 8},
    {sku: "BS-WHITE-4", FR: 7},
    {sku: "BS-WHITE-4", ES: 3},
    {sku: "BS-WHITE-4", IT: 17}]
</script>    

Unfortunately, I can't find values of keys DE, FR, IT, ES which are in other objects. Only the first GB is OK. Any help?


Solution

  • Here is a use Array.prototype.reduce to alter the shape of array

    let data = [
        {sku: "BS-WHITE-1", GB: 15, total: 0, inbound: 0, available: 0},
        {sku: "BS-WHITE-1", DE: 4},
        {sku: "BS-WHITE-1", ES: 0},
        {sku: "BS-WHITE-1", IT: 3},
        {sku: "BS-WHITE-1", FR: 0},
        {sku: "BS-WHITE-2", GB: 19, total: 40, inbound: 0, available: 40},
        {sku: "BS-WHITE-2", DE: 2},
        {sku: "BS-WHITE-2", FR: 5},
        {sku: "BS-WHITE-2", ES: 3},
        {sku: "BS-WHITE-2", IT: 6},
        {sku: "BS-WHITE-3", GB: 21, total: 51, inbound: 1, available: 50},
        {sku: "BS-WHITE-3", DE: 1},
        {sku: "BS-WHITE-3", ES: 1},
        {sku: "BS-WHITE-3", IT: 2},
        {sku: "BS-WHITE-3", FR: 2},
        {sku: "BS-WHITE-4", GB: 43, total: 42, inbound: 8, available: 31},
        {sku: "BS-WHITE-4", DE: 8},
        {sku: "BS-WHITE-4", FR: 7},
        {sku: "BS-WHITE-4", ES: 3},
        {sku: "BS-WHITE-4", IT: 17}
    ];
    
    const result = data.reduce((accumulator, current) => {
        let itemIndex = accumulator.findIndex(item => item.sku === current.sku);
        if(itemIndex != -1) {
            accumulator[itemIndex] = {...accumulator[itemIndex], ...current};
        } else {
            accumulator = accumulator.concat(current);
        }
        return accumulator;
    }, []);
    
    console.log(result);