Unable merge two differnt array as per key name using Javascript

Viewed 47

I am trying to merge two array of object as per key value pair but its giving the result which is not as expected. I am explaining all the document with my code below.

let arr1 = [
  {
    "_id": "PU2-TEXT BOOK",
    "dispatchcount": 2,
    "totalDispatchValue": 5810,
    "totalDiscountValue": 150
  },
  {
    "_id": "PU2-Mathematics Part - 1 Text Book",
    "dispatchcount": 1,
    "totalDispatchValue": 4131,
    "totalDiscountValue": 150
  },
  {
    "_id": "Boys White & Blue Striped Half Shirt",
    "dispatchcount": 1,
    "totalDispatchValue": 4131,
    "totalDiscountValue": 150
  }
]

let arr2 = [
  {
    "_id": "PU2-TEXT BOOK",
    "pendingcount": 2,
    "totalPendingValue": 14157,
    "totalPendingDiscountValue": 1518
  },
  {
    "_id": "PU2-Accountancy Part - 2 Text Book",
    "pendingcount": 1,
    "totalPendingValue": 9002,
    "totalPendingDiscountValue": 834
  }
]

let arr3 = arr1.map((item, i) => Object.assign({}, item, arr2[i]));

console.log(arr3);

Here I need to merge both arr1 and arr2 as per key _id value if any matches found then the both object will merge if not found from 2nd array then original value will remain as it is. My expected output is given below.

Expected output::

[
    {
    "_id": "PU2-TEXT BOOK" ,
    "dispatchcount": 2 ,
    "totalDispatchValue": 5810 ,
    "totalDiscountValue": 150 ,
    "pendingcount": 2 ,
    "totalPendingValue": 14157 ,
    "totalPendingDiscountValue": 1518
    },
    {
    "_id": "PU2-Mathematics Part - 1 Text Book",
    "dispatchcount": 1,
    "totalDispatchValue": 4131,
    "totalDiscountValue": 150,
    "pendingcount": 0 ,
    "totalPendingValue": 0 ,
    "totalPendingDiscountValue": 0
  },
  {
    "_id": "Boys White & Blue Striped Half Shirt",
    "dispatchcount": 1,
    "totalDispatchValue": 4131,
    "totalDiscountValue": 150,
    "pendingcount": 0 ,
    "totalPendingValue": 0 ,
    "totalPendingDiscountValue": 0
  },
  {
    "_id": "PU2-Accountancy Part - 2 Text Book",
    "pendingcount": 1,
    "totalPendingValue": 9002,
    "totalPendingDiscountValue": 834,
    "dispatchcount": 0 ,
    "totalDispatchValue": 0 ,
    "totalDiscountValue": 0 
  }
  ] 

So here i want merge two array of object as per _id key. If some where its matched then both object will merge and if object from 1st array is not present in 2nd or vise versa also it will merge with value 0 for those keys not present.

3 Answers

You can combine the arrays arr1 and arr2 and then reduce over it. Find the matching index if it exists then combine the two objects:

let arr1 = [{"_id":"PU2-TEXT BOOK","dispatchcount":2,"totalDispatchValue":5810,"totalDiscountValue":150},{"_id":"PU2-Mathematics Part - 1 Text Book","dispatchcount":1,"totalDispatchValue":4131,"totalDiscountValue":150},{"_id":"Boys White & Blue Striped Half Shirt","dispatchcount":1,"totalDispatchValue":4131,"totalDiscountValue":150}];

let arr2 = [{"_id":"PU2-TEXT BOOK","pendingcount":2,"totalPendingValue":14157,"totalPendingDiscountValue":1518},{"_id":"PU2-Accountancy Part - 2 Text Book","pendingcount":1,"totalPendingValue":9002,"totalPendingDiscountValue":834}];

const penDef = {"pendingcount":0,"totalPendingValue":0,"totalPendingDiscountValue":0}; 
const disDef = {"dispatchcount":0,"totalDispatchValue":0,"totalDiscountValue":0};

let arr3 = [...arr1, ...arr2].reduce((acc, item, i) => {
  const matchIdx = acc.findIndex(o => o._id === item._id);
  if (matchIdx >= 0) {
    newItem = { ...acc[matchIdx],
      ...item
    };
    acc[matchIdx] = newItem;
  } else {
    mergedItem = i >= arr1.length? { ...item,
      ...disDef
    } : { ...item,
      ...penDef
    };
    acc.push(mergedItem);
  }
  return acc;
}, []);

console.log(arr3);

You could take an object for default values and spread the properties to the object with same _id.

var data1 = [{ _id: "PU2-TEXT BOOK", dispatchcount: 2, totalDispatchValue: 5810, totalDiscountValue: 150 }, { _id: "PU2-Mathematics Part - 1 Text Book", dispatchcount: 1, totalDispatchValue: 4131, totalDiscountValue: 150 }, { _id: "Boys White & Blue Striped Half Shirt", dispatchcount: 1, totalDispatchValue: 4131, totalDiscountValue: 150 }],
    data2 = [{ _id: "PU2-TEXT BOOK", pendingcount: 2, totalPendingValue: 14157, totalPendingDiscountValue: 1518 }, { _id: "PU2-Accountancy Part - 2 Text Book", pendingcount: 1, totalPendingValue: 9002, totalPendingDiscountValue: 834 }],
    defaults = { _id: "", dispatchcount: 0, totalDispatchValue: 0, totalDiscountValue: 0, pendingcount: 0, totalPendingValue: 0, totalPendingDiscountValue: 0 },
    result = Object.values([...data1, ...data2].reduce((r, o) => {
        r[o._id] = { ... (r[o._id] || defaults), ...o };
        return r;
    }, {}));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Try to use Map collection to have unique items and then just map them:

let  restProperties = { dispatchcount: 0, totalDispatchValue: 0, totalDiscountValue: 0, 
    pendingcount: 0, totalPendingValue: 0, totalPendingDiscountValue: 0 };
let uniqueArr2 = new Map(arr2.map((s)=>([s._id, s])));
arr1 = arr1.map(({_id, ...rest}) => ({_id, ...restProperties, ...rest, 
   ...uniqueArr2.get(_id) }));
const other = arr2.filter(f => !arr1.some(s=> s._id == f._id)).map(s => 
    ({...restProperties, ...s  }));
console.log([...arr1, ...other]);

An example:

let arr1 = [
{
  "_id": "PU2-TEXT BOOK",
  "dispatchcount": 2,
  "totalDispatchValue": 5810,
  "totalDiscountValue": 150
},
{
  "_id": "PU2-Mathematics Part - 1 Text Book",
  "dispatchcount": 1,
  "totalDispatchValue": 4131,
  "totalDiscountValue": 150
},
{
  "_id": "Boys White & Blue Striped Half Shirt",
  "dispatchcount": 1,
  "totalDispatchValue": 4131,
  "totalDiscountValue": 150
}
  ]

  let arr2 = [
{
  "_id": "PU2-TEXT BOOK",
  "pendingcount": 2,
  "totalPendingValue": 14157,
  "totalPendingDiscountValue": 1518
},
{
  "_id": "PU2-Accountancy Part - 2 Text Book",
  "pendingcount": 1,
  "totalPendingValue": 9002,
  "totalPendingDiscountValue": 834
}
  ]

let  restProperties = { dispatchcount: 0, totalDispatchValue: 0, totalDiscountValue: 0, pendingcount: 0, totalPendingValue: 0, totalPendingDiscountValue: 0 };
let uniqueArr2 = new Map(arr2.map((s)=>([s._id, s])));
arr1 = arr1.map(({_id, ...rest}) => ({_id, ...restProperties, ...rest, ...uniqueArr2.get(_id) }));
const other = arr2.filter(f => !arr1.some(s=> s._id == f._id)).map(s => ({...restProperties, ...s  }));
console.log([...arr1, ...other]);

Related