90

I have multiple JSON like those

var object1 = {name: "John"};
var object2 = {location: "San Jose"};

They are not nesting or anything like that. Just basically different fields. I need to combine them into one single JSON in node.js like this:

{name: "John", location: "San Jose"}

I can use jQuery just fine. Here is a working example in the browser:

http://jsfiddle.net/qhoc/agp54/

But if I do this in node.js, I don't want to load jQuery (which is a bit over use, plus node.js' jQuery doesn't work on my Windows machine).

So is there a simple way to do things similar to $.extend() without jQuery?

HP.
  • 19,226
  • 53
  • 154
  • 253
  • 2
    If you're doing various things like this, you might want to consider using [Underscore](http://underscorejs.org/#extend), which is available as a [Node module](https://npmjs.org/package/underscore). – James Allardice Feb 20 '13 at 08:09
  • 1
    `npm install extend`, [Port of jQuery.extend for Node.js](https://github.com/justmoon/node-extend). – Joel Purra Dec 14 '13 at 14:34
  • FYI Object.assign does this, but unfortunately it's not currently supported. Hopefully someday soon! https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign – Rene Wooller Mar 30 '15 at 00:54
  • 1
    That's not JSON, you're just creating standard JS objects using literal notation. (E.g. in JSON keys must be strings). And when you're 'combining' those object it has zero to do with JSON. – UpTheCreek Oct 26 '16 at 06:36

18 Answers18

143

You should use "Object.assign()"

There's no need to reinvent the wheel for such a simple use case of shallow merging.

The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.

var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign(o1, o2, o3);
console.log(obj);       // { a: 1, b: 2, c: 3 }
console.log(o1);        // { a: 1, b: 2, c: 3 }, target object itself is changed
console.log(obj === o1) // true

Even the folks from Node.js say so:

_extend was never intended to be used outside of internal NodeJS modules. The community found and used it anyway. It is deprecated and should not be used in new code. JavaScript comes with very similar built-in functionality through Object.assign.


Update:

You could use the spread operator

Since version 8.6, it's possible to natively use the spread operator in Node.js. Example below:

let o1 = { a: 1 };
let o2 = { b: 2 };
let obj = { ...o1, ...o2 }; // { a: 1, b: 2 }

Object.assign still works, though.


**PS1**: If you are actually interested in **deep merging** (in which internal object data -- in any depth -- is recursively merged), you can use packages like [deepmerge][4], [assign-deep][5] or [lodash.merge][6], which are pretty small and simple to use. **PS2**: Keep in mind that **Object.assign doesn't work with 0.X versions of Node.js**. If you are working with one of those versions (_you really shouldn't by now_), you could use `require("util")._extend` as shown in the Node.js link above -- for more details, check [tobymackenzie's answer to this same question](https://stackoverflow.com/a/22286375/36272).
Ricardo Nolde
  • 33,390
  • 4
  • 36
  • 40
  • 1
    +1 To anyone coming here looking for a native _browser_ alternative, note this is an ES6 feature and as such [not well supported yet](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign). – Boaz Nov 14 '16 at 08:03
  • Adding to [Boaz](http://stackoverflow.com/users/1889273/boaz) comment, in the Mozilla link for `Object.assign` above, you can find a polyfill that works just fine in a browser. – Ricardo Nolde Jan 13 '17 at 03:11
  • 4
    Call it with an empty first argument to avoid accidentally mangling your objects: `var obj = Object.assign({}, o1, o2, o3)` – pguardiario Oct 01 '17 at 03:04
58

If using Node version >= 4, use Object.assign() (see Ricardo Nolde's answer).

If using Node 0.x, there is the built in util._extend:

var extend = require('util')._extend
var o = extend({}, {name: "John"});
extend(o,  {location: "San Jose"});

It doesn't do a deep copy and only allows two arguments at a time, but is built in. I saw this mentioned on a question about cloning objects in node: https://stackoverflow.com/a/15040626.

If you're concerned about using a "private" method, you could always proxy it:

// myutil.js
exports.extend = require('util')._extend;

and replace it with your own implementation if it ever disappears. This is (approximately) their implementation:

exports.extend = function(origin, add) {
    if (!add || (typeof add !== 'object' && add !== null)){
        return origin;
    }

    var keys = Object.keys(add);
    var i = keys.length;
    while(i--){
        origin[keys[i]] = add[keys[i]];
    }
    return origin;
};
tobymackenzie
  • 818
  • 6
  • 12
  • 5
    The underscore in _extend represents a private method, meaning it is not intended for public use. Not only is this method undocumented, but the implementation could change in any revision, affecting your project. – aaaaaa May 30 '15 at 17:49
  • 3
    As @jimbojw mentioned in a comment on the linked answer, Isaacs says ["You can go ahead and use `util._extends()` … It's not going anywhere any time soon"](https://github.com/joyent/node/pull/4834#issuecomment-13981250). There is further discussion in that thread. If you are worried, read through and make a decision for your project. – tobymackenzie May 30 '15 at 21:59
  • npm install util-extend – Maciej Krawczyk Mar 17 '17 at 18:15
  • 1
    the `_extend()` function has beeen deprecated in favor of `Object.Assign()` - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign – brasskazoo Jan 05 '18 at 00:03
51

Underscore's extend is the easiest and quickest way to achieve this, like James commented.

Here's an example using underscore:

var _ = require('underscore'), // npm install underscore to install
  object1 = {name: "John"},
  object2 = {location: "San Jose"};

var target = _.extend(object1, object2);

object 1 will get the properties of object2 and be returned and assigned to target. You could do it like this as well, depending on whether you mind object1 being modified:

var target = {};
_.extend(target, object1, object2);
Antonio Pérez
  • 6,702
  • 4
  • 36
  • 61
AndyD
  • 5,252
  • 35
  • 32
  • 1
    Thanks. But like to avoid underscore in node.js too if I can. – HP. Feb 20 '13 at 17:49
  • 1
    I just have a light node.js app with just express and mailjs. Just don't want to load with other libs if I only use one function. Ur idea is still cool though. Thanks. – HP. Feb 20 '13 at 23:21
  • 10
    Beware, underscore's extend is only at first level. It cannot merge subojects. – Feugy Apr 29 '14 at 07:33
42

A normal loop?

function extend(target) {
    var sources = [].slice.call(arguments, 1);
    sources.forEach(function (source) {
        for (var prop in source) {
            target[prop] = source[prop];
        }
    });
    return target;
}

var object3 = extend({}, object1, object2);

That's a basic starting point. You may want to add things like a hasOwnProperty check, or add some logic to handle the case where multiple source objects have a property with the same identifier.

Here's a working example.

Side note: what you are referring to as "JSON" are actually normal JavaScript objects. JSON is simply a text format that shares some syntax with JavaScript.

James Allardice
  • 164,175
  • 21
  • 332
  • 312
  • I use this function to merge two json. But the reultant json is prefexed with '0'. Example 0 : {kye : value}. Please help me how do i prefix with my own string instead of '0'? – Saurabh Ghewari Sep 19 '14 at 12:51
  • 7
    Down voted cause this is one of the cases where people, especially newbies, should be directed to tested libraries. – Martin Wawrusch Nov 22 '14 at 18:19
  • @James I'm a newbie to react. your solution says it is taking 3 arguments where as one is expected for extend. Please suggest what change I need to make. – vinny Jan 21 '21 at 19:37
  • @vinny don't use this, please; why is this still marked as correct answer? – Ricardo Nolde Mar 23 '21 at 01:45
15

Use merge.

$ npm install merge

Sample code:

var merge = require('merge'), // npm install -g merge
    original, cloned;

console.log(

    merge({ one: 'hello' }, { two: 'world' })

); // {"one": "hello", "two": "world"}

original = { x: { y: 1 } };

cloned = merge(true, original);

cloned.x.y++;

console.log(original.x.y, cloned.x.y); // 1, 2
zim
  • 516
  • 8
  • 8
12

I see that this thread is too old, but I put my answer here just in logging purposes.

In one of the comments above you mentioned that you wanted to use 'express' in your project which has 'connect' library in the dependency list. Actually 'connect.utils' library contains a 'merge' method that does the trick. So you can use the 3rd party implementation without adding any new 3rd party libraries.

Develop4Life
  • 7,581
  • 8
  • 58
  • 76
Petr KOKOREV
  • 373
  • 1
  • 3
  • 7
11

Here is simple solution, to merge JSON. I did the following.

  • Convert each of the JSON to strings using JSON.stringify(object).
  • Concatenate all the JSON strings using + operator.
  • Replace the pattern /}{/g with ","
  • Parse the result string back to JSON object

    var object1 = {name: "John"};
    var object2 = {location: "San Jose"};
    var merged_object = JSON.parse((JSON.stringify(object1) + JSON.stringify(object2)).replace(/}{/g,","))
    

The resulting merged JSON will be

{name: "John", location: "San Jose"}
Manu K Mohan
  • 823
  • 4
  • 9
  • 29
  • Would this work if there is { or } inside the double quote (value)? I am always hesitate to hack string. – HP. Feb 20 '13 at 17:48
  • @HP.Yes it will work. This is pretty straight forward simple regex /}{/, no need to worry about string manipulation. :-) – Manu K Mohan Feb 21 '13 at 03:46
  • 1
    Unfortunately, it doesn't work if `object2 = {}` since the final characters to be parsed are `,}`. Can be solved by adding, after the replace: `.replace(/,}^/, '}')` – Hassen Mar 03 '13 at 16:40
  • 3
    Use any number of arguments, no matter if any one is empty with http://gist.github.com/rxaviers/6734630 – Rafael Xavier Sep 27 '13 at 21:51
  • Props to @RafaelXavier His gist turns this answer into a usable function. – scarver2 Nov 03 '13 at 23:08
  • Please, by advised this doesn't handle deeply JSON merge. Explanation and solution for deep merge here: https://gist.github.com/rxaviers/6734630/#comment-943271 (also commented here http://stackoverflow.com/questions/14974864/combine-or-merge-json-on-node-js-without-jquery/14974931#comment28268748_14974931) – Rafael Xavier Nov 04 '13 at 10:41
  • This is an interesting way of doing it. But please don't do this in production. Its difficult to understand and requires the reasonably expensive operations of stringifying and parsing multiple objects. Use a library. – Jack Ryan Feb 26 '15 at 10:42
  • This wouldn't work in many special cases. And also it's a bad decision to convert objects to strings and convert them back after modification. If you need to modify objects, work with objects. – Sergei Kovalenko Mar 07 '16 at 13:53
5

There is an easy way of doing it in Node.js

var object1 = {name: "John"};
var object2 = {location: "San Jose"};

To combine/extend this we can use ... operator in ECMA6

var object1 = {name: "John"};
var object2 = {location: "San Jose"};

var result = {
  ...object1,
  ...object2
}

console.log(result)
Stenal P Jolly
  • 737
  • 9
  • 20
4

Use spread operator. It is supported in Node since version 8.6

const object1 = {name: "John"};
const object2 = {location: "San Jose"};

const obj = {...object1, ...object2}

console.log(obj)
//   {
//     "name": "John",
//     "location": "San Jose"
//   }
  • 2
    Hi Khaled, you should try to explain what the spread operator does as this will improve your post. Explanations are far better than just stating code. It is also a duplicate of answer already posted. – R. Chappell Sep 25 '18 at 15:05
3

You can also use this lightweight npm package called absorb

It is 27 lines of code, 1kb and uses recursion to perform deep object merges.

var absorb = require('absorb');
var obj1, obj2;

obj1 = { foo: 123, bar: 456 };
obj2 = { bar: 123, key: 'value' }

absorb(obj1, obj2);

console.log(obj1); // Output: { foo: 123, bar: 123, key: 'value' }

You can also use it to make a clone or only transfer values if they don't exist in the source object, how to do this is detailed in the link provided.

Patrick Murphy
  • 2,311
  • 14
  • 17
3

It can easy be done using Object.assign() method -

 var object1 = {name: "John"};
 var object2 = {location: "San Jose"};
 var object3 = Object.assign(object1,object2);
 console.log(object3);

now object3 is { name: 'John', location: 'San Jose' }

Sushil Kumar
  • 159
  • 10
  • In your example, `object1` is also modified. [Check my answer](http://stackoverflow.com/a/37336592/36272) for more details. – Ricardo Nolde Feb 13 '17 at 06:07
2

If you need special behaviors like nested object extension or array replacement you can use Node.js's extendify.

var extendify = require('extendify');

_.extend = extendify({
    inPlace: false,
    arrays : 'replace',
    isDeep: true
});

obj1 = {
    a:{
        arr: [1,2]
    },
    b: 4
};

obj2 = {
    a:{
        arr: [3]
    }
};

res = _.extend(obj1,obj2);
console.log(JSON.stringify(res)); //{'a':{'arr':[3]},'b':4}
2

Lodash is a another powerful tool-belt option for these sorts of utilities. See: _.merge() (which is recursive)

var object = {
  'a': [{ 'b': 2 }, { 'd': 4 }]
};
var other = {
  'a': [{ 'c': 3 }, { 'e': 5 }]
}; 
_.merge(object, other);
// => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } 
JoshuaDavid
  • 8,861
  • 8
  • 47
  • 55
1

The below code will help you to merge two JSON object which has nested objects.

function mergeJSON(source1,source2){
    /*
     * Properties from the Souce1 object will be copied to Source2 Object.
     * Note: This method will return a new merged object, Source1 and Source2 original values will not be replaced.
     * */
    var mergedJSON = Object.create(source2);// Copying Source2 to a new Object

    for (var attrname in source1) {
        if(mergedJSON.hasOwnProperty(attrname)) {
          if ( source1[attrname]!=null && source1[attrname].constructor==Object ) {
              /*
               * Recursive call if the property is an object,
               * Iterate the object and set all properties of the inner object.
              */
              mergedJSON[attrname] = zrd3.utils.mergeJSON(source1[attrname], mergedJSON[attrname]);
          } 

        } else {//else copy the property from source1
            mergedJSON[attrname] = source1[attrname];

        }
      }

      return mergedJSON;
}
shibualexis
  • 4,534
  • 3
  • 20
  • 25
1

You can use Lodash

const _ = require('lodash');

let firstObject = {'email' : 'email@email.com'};
let secondObject = { 'name' : { 'first':message.firstName } };
_.merge(firstObject, secondObject)
      
Radon8472
  • 4,285
  • 1
  • 33
  • 41
Aslan Varoqua
  • 191
  • 1
  • 6
0

A better approach from the correct solution here in order to not alter target:

function extend(){
  let sources = [].slice.call(arguments, 0), result = {};
  sources.forEach(function (source) {
    for (let prop in source) {
      result[prop] = source[prop];
    }
  });
  return result;
}
Dody
  • 608
  • 7
  • 19
0

You can do it inline, without changing any variables like this:

let obj1 = { name: 'John' };
let obj2 = { surname: 'Smith' };
let obj = Object.assign({}, obj1, obj2); // { name: 'John', surname: 'Smith' }
Emre Tapcı
  • 1,743
  • 17
  • 16
-3

Let object1 and object2 be two JSON object.

var object1 = [{"name": "John"}];
var object2 = [{"location": "San Jose"}];

object1.push(object2);

This will simply append object2 in object1:

[{"name":"John"},{"location":"San Jose"}]
Remi Guan
  • 21,506
  • 17
  • 64
  • 87
  • This isn't what the OP asked. You're showing how to build an array of JSON objects. The OP asked for a way to combine key:value pairs from multiple JSON objects into a single one. – David Makogon Jul 04 '16 at 03:12