1

I have 2 arrays of objects:

array1 = [{"id":1,"cost":200,"qty":56},{"id":2,"cost":100,"qty":16}];
array2 = [{"id":1,"cost":200,"desc":"a good one"},{"id":2,"cost":100,"desc":"a bad one"},{"id":3,"cost":50,"desc":"an okay one"}];

I want to merge them so it looks like this:

[{"id":1,"cost":200,"qty":56,"desc":"a good one"},{"id":2,"cost":100,"qty":16,"desc":"a bad one"}];

Please notice the new array has properties from both arrays but it left out the object that was not present in the first one.

I tried this:

var mergethem = function() {
     var array1 = [{"id":1,"cost":200,"qty":56},{"id":2,"cost":100,"qty":16}];
     var array2 = [{"id":1,"cost":200,"desc":"a good one"},{"id":2,"cost":100,"desc":"a bad one"},{"id":3,"cost":50,"desc":"an okay one"}];
    
     var newarray= array2.filter(i => array1.map(a=> { if(a.id == i.id) i.qty = a.qty; return i; }));
     
     return newarray.filter(i=> { if(i.qty) return i; });
    }
    
    console.log(mergethem());

this seems to work sometimes and some times it doesn't depending on the environment. I can't pinpoint what the problem is so I would like to ask for alternatives to try out.

halfer
  • 19,824
  • 17
  • 99
  • 186
Cain Nuke
  • 2,843
  • 5
  • 42
  • 65
  • 1
    what error do you get? – Nina Scholz Apr 04 '23 at 21:04
  • The 3rd element is included too even though is supposed to be left out. – Cain Nuke Apr 04 '23 at 22:01
  • Does this answer your question? [Merge two array of objects based on a key](https://stackoverflow.com/questions/46849286/merge-two-array-of-objects-based-on-a-key) – pilchard Apr 04 '23 at 23:00
  • and [JavaScript merging objects by id](https://stackoverflow.com/questions/19480008/javascript-merging-objects-by-id) or [How to merge arrays of objects by Id key?](https://stackoverflow.com/questions/74477195/how-to-merge-arrays-of-objects-by-id-key) or [Merge two array of objects based on same key and value](https://stackoverflow.com/questions/66741871/merge-two-array-of-objects-based-on-same-key-and-value/66746540#66746540) – pilchard Apr 04 '23 at 23:00

2 Answers2

2

You could get references of the objects of the second array and map the first while adding properties of the second array, if exist.

const
    array1 = [{ id: 1, cost: 200, qty: 56 }, { id: 2, cost: 100, qty: 16 }],
    array2 = [{ id: 1, cost: 200, desc: "a good one" }, { id: 2, cost: 100, desc: "a bad one" }, { id: 3, cost: 50, desc: "an okay one" }],
    references2 = Object.fromEntries(array2.map(o => [o.id, o])),
    result = array1.map(o => ({ ...o, ...references2[o.id] }));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • You already posted comment that this solution is more robust, awesome! The only thing worth mentioning - that we need somehow be sure that 'o.id' is in our array of references - otherwise we would get 'undefined' I believe? – ByteMaster Apr 04 '23 at 21:33
  • Sorry but I get this error: Object.fromEntries I am on node.js – Cain Nuke Apr 04 '23 at 22:15
  • @ByteMaster, `undefined` spreads in objects into as empty object. – Nina Scholz Apr 05 '23 at 06:43
  • @CainNuke, mabe you take a new edition of node. does spreading `...` works? – Nina Scholz Apr 05 '23 at 06:45
  • probably but I dont wanna risk breaking my whole application by upgrading node. – Cain Nuke Apr 05 '23 at 07:00
  • you could replace this line `references2 = Object.fromEntries(array2.map(o => [o.id, o])),` with `references2 = array2.reduce((r, o) => (r[o.id] = o, r), {}),` which creates an object. – Nina Scholz Apr 05 '23 at 07:13
1

const array1 = [
  {"id":1,"cost":200,"qty":56},
  {"id":2,"cost":100,"qty":16}
];

const array2 = [
  {"id":1,"cost":200,"desc":"a good one"},
  {"id":2,"cost":100,"desc":"a bad one"},
  {"id":3,"cost":50,"desc":"an okay one"}
];

const result = array1.reduce((previousValue, currentValue) => {
  const needObj = array2.find(o => o.id === currentValue.id) ?? {};
  previousValue.push({...currentValue, ...needObj});
  return previousValue;
}, []);

console.log(result);
imhvost
  • 4,750
  • 2
  • 8
  • 10
  • 1
    this works only if the items are at the same index for merging. even op is usning a find function and checks `id` of both arrays. – Nina Scholz Apr 04 '23 at 21:31
  • Cool, cool - it takes me a while to understand why and how this works. Thanks for such an interesting approach! Basically trick here is that secondly 'spread-ed' object would be iterated over all keys - and all of the keys would be written into object A! And because we have same value for the 'id' key - we would get expanded object! – ByteMaster Apr 04 '23 at 21:31
  • @Nina Scholz , yes, or maybe the objects go sequentially? )) But you are right, I have edited the answer according to your comment. Thank you! – imhvost Apr 04 '23 at 21:43
  • Sorry I get this error: Unexpected token ? (the one before `{};`) – Cain Nuke Apr 04 '23 at 22:18
  • I might as well just take that part out like this: `const needObj = array2.find(o => o.id === currentValue.id);` seems to work anyway – Cain Nuke Apr 04 '23 at 22:24
  • `??` - This is [nullish coalescing operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing). It is surprising that you are getting an error, because it works in all modern browsers. But you can check `needObj` for `undefined` use `if (needObj) { previousValue.push( { ...currentValue, ...needObj } ); }` – imhvost Apr 05 '23 at 07:41