21

I am trying to merge the following objects into one but having no luck so far - the structure is as follows in my console.log :

    2018-05-11 : {posts: 2} // var posts
    2018-05-11 : {notes: 1} // var notes

Once merged I want it to look like the following

2018-05-11 : {posts: 2, notes: 1}

I have tried object.assign() but it is just removing the initial posts data - what is the best approach for this?

Zabs
  • 13,852
  • 45
  • 173
  • 297
  • Object.assign should work. `Object.assign( a, b )` if you want to add b to a. `Object.assign( {}, a, b )` if you want to add both a and b to a new object. Can you show the `Object.assign()` code you tried? – Shilly May 04 '18 at 13:49
  • Have you seen [this](https://stackoverflow.com/questions/171251/how-can-i-merge-properties-of-two-javascript-objects-dynamically) question? – Federico klez Culloca May 04 '18 at 13:49
  • Remember that `keys` are unique. It is easy to loop over it like this. – deEr. May 04 '18 at 13:55
  • 1
    @stdob-- AKA mods this is not a duplicate of the suggested link as this question has the same index for each object which presents an issue due to shallow copy. – Wancieho May 15 '19 at 14:49
  • This question would be clearer (and more clearly not a duplicate), it Zabs presented the code snippet he tried (which didn't do what he wanted). Based on the accepted answer, and his description of what went wrong when he used object.assign, it appears that he reads `2018-05-11 : {posts: 2}` into javascript as an object similar to `{'2018-05-11': {posts: 2}}`. Attempting to merge two such objects then runs into the problem that `assign` is a shallow copy. – ToolmakerSteve Oct 03 '19 at 21:10
  • Hmm. Reading further down in the proposed duplicate, I see there are answers describing how to copy with *deep merge* (objects with same key). See https://stackoverflow.com/a/383245/199364 and others. So my proposal to re-open can be ignored. (At first, like Wancieho, I thought the other Q&A only discussed *shallow merge*.) – ToolmakerSteve Oct 03 '19 at 21:20

6 Answers6

16

var x =  {posts: 2};
var y = {notes: 1};
var z = Object.assign( {}, x, y );
console.log(z);

Use Object.assign() and assign object properties to empty object.

Atul Sharma
  • 9,397
  • 10
  • 38
  • 65
  • 1
    this is completely wrong based on the result he asked for. – Wancieho May 15 '19 at 14:40
  • @Wancieho It's exactly right based on the result OP asked for. You're just assuming a data structure not shown in evidence. MayK's answer is _also_ right, but at least shows for _which_ data structure it would be correct. – Auspex Jun 13 '19 at 13:34
  • 1
    @Auspex umm, did you even look at the output of this answer VS what the OP wanted? This answer is missing the `2018-05-11` key – Wancieho Jun 14 '19 at 17:17
  • 3
    Don't be insulting. The OP does not, in fact, state that the date is a key. It says these are _log_ records. You have merely jumped to an assumption. I'm not the person who failed to read the question. – Auspex Jun 16 '19 at 23:06
  • It can be deduced from OP's statement *"I have tried object.assign() but it is just removing the initial posts data"* that he has two objects with same key. So this answer won't help him. Or anyone else with a similar symptom. – ToolmakerSteve Oct 03 '19 at 21:16
4

You can do the following with Object.assign():

var posts = {'2018-05-11' : {posts: 2}} // var posts
var notes = {'2018-05-11' : {notes: 1}} // var notes

Object.assign(posts['2018-05-11'], notes['2018-05-11']);
console.log(posts);
Mamun
  • 66,969
  • 9
  • 47
  • 59
4

Here's a function that's a bit more generic. It propagates through the object and will merge into a declared variable.

const posts = {  '2018-05-11': {    posts: 2  },  '2018-05-12': {    posts: 5  }};
const notes = {  '2018-05-11': {    notes: 1  },  '2018-05-12': {    notes: 3  }};

function objCombine(obj, variable) {
  for (let key of Object.keys(obj)) {
    if (!variable[key]) variable[key] = {};

    for (let innerKey of Object.keys(obj[key]))
      variable[key][innerKey] = obj[key][innerKey];
  }
}

let combined = {};
objCombine(posts, combined);
objCombine(notes, combined);
console.log(combined)

I hope you find this helpful.

Andrew Bone
  • 7,092
  • 2
  • 18
  • 33
  • NOTE: This is neither a shallow merge nor a deep merge. I'm not sure of the exact terminology, but it merges "one level deeper" than a shallow merge would. Sufficient for OP's question. The deep equivalent would *recurse*: replace the two lines starting with `for (let innerkey ...`, with `objCombine(obj[key], variable[key])`. I think - not tested. – ToolmakerSteve Oct 03 '19 at 21:31
3

You could use merge method from Lodash library.

const posts = {'2018-05-11' : {posts: 2}}
const notes = {'2018-05-11' : {notes: 1}}

const result = _.merge({}, posts, notes);
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
  • 1
    I tend to prefer lodash, as it offers defensiveness around things such as one of those objects NOT being an object, and preventing nasty js errors... – random_user_name May 04 '18 at 13:52
  • @nenad install a library to perform something with plain JS? I think not... – Wancieho May 15 '19 at 14:37
  • @Wancieho Nobody suggested installing a library. The simple fact is that most of us _are_ using libraries, and a great number are using lodash. If you are, then it may well be worth using `merge` as cale_b suggests. – Auspex Jun 13 '19 at 13:37
  • @Auspex install/embed whatever you wanna call it it's unnecessary overhead. Offering a solution that requires another unneeded dependency is not correct. There is nothing to debate. – Wancieho Jun 14 '19 at 17:15
  • If you already have lodash, there's no overhead. SO is about getting as many answers as possible, not a single theoretically correct answer. Yes, there's no evidence that it's the best answer for the OP, but I guarantee that it will be the best answer for some who come here – Auspex Jun 16 '19 at 23:09
2

you need to apply assign to each item like this:

var a =  {"2018-05-11" : {notes: 1}};

var b =  {"2018-05-11" : {posts: 3}};

var result = {};

Object.keys(a).forEach(k=>{result[k] = Object.assign(a[k],b[k])});

console.log(result);
MayK
  • 1,269
  • 1
  • 10
  • 24
1

jQuery.extend() might help.

The merge performed by $.extend() is not recursive by default; if a property of the first object is itself an object or array, it will be completely overwritten by a property with the same key in the second or subsequent object. The values are not merged. However, by passing true for the first function argument, objects will be recursively merged.

Try

$.extend(obj1, obj2)
Salman Malik
  • 923
  • 6
  • 24
M Ciel
  • 85
  • 7