How to Merge JSON
2025/05/20
9 min read

How to Merge JSON

Comprehensive guide to merging JSON objects in different programming languages

Introduction to JSON Merging

Merging JSON objects is a fundamental operation in data processing, configuration management, and API interactions. Whether you're combining user settings, merging configuration files, or aggregating API responses, understanding how to properly merge JSON objects is crucial for modern development.

JSON merging refers to the process of combining two or more JSON objects into a single unified object. This process can be simple for flat objects but becomes more complex when dealing with nested structures, arrays, and conflicting values.

Basic JSON Merging Concepts

Before diving into implementation details, it's important to understand some key concepts related to JSON merging:

Shallow vs Deep Merging

  • Shallow Merging: Only the top-level properties are combined. When both objects contain the same property, the value from the second object overwrites the first.
  • Deep Merging: The merge operation recursively traverses the object tree, combining nested objects rather than replacing them.

Merge Strategies for Conflicting Values

When merging JSON objects, conflicting values can be handled in several ways:

StrategyDescriptionUse Case
Last WinsValue from the last object overrides earlier valuesDefault configurations
First WinsValue from the first object is preservedPreserving user settings
Custom LogicApply specific logic for different propertiesComplex business rules
Error on ConflictRaise an error when conflicts are detectedCritical data integrity

JavaScript Methods for Merging JSON

JavaScript offers several built-in methods for merging JSON objects:

Using Object.assign()

The Object.assign() method performs a shallow merge, copying all enumerable own properties from source objects to a target object.

const json1 = { name: "John", age: 30 };
const json2 = { city: "New York", age: 31 };

const merged = Object.assign({}, json1, json2);
console.log(merged);
// Output: { name: "John", city: "New York", age: 31 }

Note that properties with the same key are overwritten by objects that come later in the parameters list.

Using Spread Operator (...)

The spread operator provides a more concise way to merge objects:

const json1 = { name: "John", age: 30 };
const json2 = { city: "New York", age: 31 };

const merged = { ...json1, ...json2 };
console.log(merged);
// Output: { name: "John", city: "New York", age: 31 }

This method also overwrites duplicate keys with values from later objects.

Deep Merging JSON Objects

Both Object.assign() and the spread operator perform shallow merges. For nested objects, you need a deep merge implementation:

Recursive Deep Merge Function

function deepMerge(target, source) {
  const output = Object.assign({}, target);
  
  if (isObject(target) && isObject(source)) {
    Object.keys(source).forEach(key => {
      if (isObject(source[key])) {
        if (!(key in target)) {
          Object.assign(output, { [key]: source[key] });
        } else {
          output[key] = deepMerge(target[key], source[key]);
        }
      } else {
        Object.assign(output, { [key]: source[key] });
      }
    });
  }
  
  return output;
}

function isObject(item) {
  return (item && typeof item === 'object' && !Array.isArray(item));
}

// Usage
const json1 = { 
  name: "John", 
  address: { 
    city: "New York", 
    zip: 10001 
  } 
};

const json2 = { 
  name: "Jane", 
  address: { 
    state: "NY" 
  } 
};

const merged = deepMerge(json1, json2);
console.log(merged);
// Output: { 
//   name: "Jane", 
//   address: { 
//     city: "New York", 
//     zip: 10001, 
//     state: "NY" 
//   } 
// }

Using Libraries for Merging JSON

For more complex merging scenarios, consider using established libraries:

Lodash's merge and mergeWith

Lodash provides robust functions for deep merging:

const _ = require('lodash');

const json1 = { user: { name: "John", data: [1, 2] } };
const json2 = { user: { age: 30, data: [3, 4] } };

// Basic deep merge
const merged1 = _.merge({}, json1, json2);
console.log(merged1);
// Output: { user: { name: "John", age: 30, data: [3, 4] } }

// Custom merge with mergeWith
const merged2 = _.mergeWith({}, json1, json2, (objValue, srcValue) => {
  if (Array.isArray(objValue)) {
    return objValue.concat(srcValue);
  }
});
console.log(merged2);
// Output: { user: { name: "John", age: 30, data: [1, 2, 3, 4] } }

deepmerge Package

The deepmerge npm package is specifically designed for deep merging:

const deepmerge = require('deepmerge');

const json1 = { user: { name: "John", hobbies: ["reading"] } };
const json2 = { user: { age: 30, hobbies: ["swimming"] } };

// Default merge (concatenates arrays)
const merged = deepmerge(json1, json2);
console.log(merged);
// Output: { user: { name: "John", age: 30, hobbies: ["reading", "swimming"] } }

// Custom array merge
const overwriteMerge = (destinationArray, sourceArray) => sourceArray;
const options = { arrayMerge: overwriteMerge };
const mergedCustom = deepmerge(json1, json2, options);
console.log(mergedCustom);
// Output: { user: { name: "John", age: 30, hobbies: ["swimming"] } }

Merging JSON in Other Languages

Python

Using the built-in dictionary update method:

import json

json1_str = '{"name": "John", "age": 30}'
json2_str = '{"city": "New York", "age": 31}'

# Parse JSON strings to dictionaries
json1 = json.loads(json1_str)
json2 = json.loads(json2_str)

# Merge dictionaries
merged = {**json1, **json2}  # Python 3.5+

# Convert back to JSON string
merged_json = json.dumps(merged)
print(merged_json)
# Output: {"name": "John", "city": "New York", "age": 31}

For deep merging in Python:

def deep_merge(dict1, dict2):
    result = dict1.copy()
    for key, value in dict2.items():
        if key in result and isinstance(result[key], dict) and isinstance(value, dict):
            result[key] = deep_merge(result[key], value)
        else:
            result[key] = value
    return result

json1 = {"user": {"name": "John", "settings": {"theme": "dark"}}}
json2 = {"user": {"age": 30, "settings": {"notifications": True}}}

merged = deep_merge(json1, json2)
print(merged)
# Output: {'user': {'name': 'John', 'settings': {'theme': 'dark', 'notifications': True}, 'age': 30}}

Ruby

Using the Hash#merge method:

require 'json'

json1_str = '{"name": "John", "age": 30}'
json2_str = '{"city": "New York", "age": 31}'

# Parse JSON strings to hashes
json1 = JSON.parse(json1_str)
json2 = JSON.parse(json2_str)

# Merge hashes
merged = json1.merge(json2)

# Convert back to JSON string
merged_json = JSON.generate(merged)
puts merged_json
# Output: {"name":"John","city":"New York","age":31}

For deep merging in Ruby:

require 'json'

# Ruby's built-in deep_merge
require 'active_support/core_ext/hash/deep_merge'

json1 = JSON.parse('{"user": {"name": "John", "settings": {"theme": "dark"}}}')
json2 = JSON.parse('{"user": {"age": 30, "settings": {"notifications": true}}}')

merged = json1.deep_merge(json2)
puts JSON.generate(merged)
# Output: {"user":{"name":"John","settings":{"theme":"dark","notifications":true},"age":30}}

Special Merging Cases

Merging Arrays

When merging JSON objects containing arrays, you have several strategies:

  1. Replace: Later arrays completely replace earlier ones
  2. Concatenate: Combine the elements of both arrays
  3. Merge by index: Merge array elements at the same positions
  4. Merge by ID: Merge array elements based on an identifier field
// Concatenate arrays example
const json1 = { tags: ["important", "urgent"] };
const json2 = { tags: ["completed", "archived"] };

const merged = {
  ...json1,
  tags: [...json1.tags, ...json2.tags]
};
console.log(merged);
// Output: { tags: ["important", "urgent", "completed", "archived"] }

// Merge arrays by ID example
const users1 = { users: [{ id: 1, name: "John" }, { id: 2, name: "Jane" }] };
const users2 = { users: [{ id: 1, age: 30 }, { id: 3, name: "Bob", age: 25 }] };

function mergeArraysById(arr1, arr2, idKey) {
  const merged = [...arr1];
  
  arr2.forEach(item2 => {
    const item1Index = merged.findIndex(item1 => item1[idKey] === item2[idKey]);
    
    if (item1Index >= 0) {
      merged[item1Index] = { ...merged[item1Index], ...item2 };
    } else {
      merged.push(item2);
    }
  });
  
  return merged;
}

const mergedUsers = {
  users: mergeArraysById(users1.users, users2.users, 'id')
};

console.log(mergedUsers);
// Output: {
//   users: [
//     { id: 1, name: "John", age: 30 },
//     { id: 2, name: "Jane" },
//     { id: 3, name: "Bob", age: 25 }
//   ]
// }

Handling null and undefined Values

When merging objects, you need to decide how to handle null and undefined values:

const json1 = { name: "John", age: null, city: undefined };
const json2 = { age: 30 };

// Default behavior (null values are copied, undefined are ignored)
const merged1 = Object.assign({}, json1, json2);
console.log(merged1);
// Output: { name: "John", age: 30 }

// Custom handling in deep merge
function customDeepMerge(target, source) {
  const output = Object.assign({}, target);
  
  if (isObject(target) && isObject(source)) {
    Object.keys(source).forEach(key => {
      // Skip null values in source
      if (source[key] === null) return;
      
      if (isObject(source[key])) {
        if (!(key in target)) {
          output[key] = source[key];
        } else {
          output[key] = customDeepMerge(target[key], source[key]);
        }
      } else {
        output[key] = source[key];
      }
    });
  }
  
  return output;
}

Command Line Tools for Merging JSON

Using jq

jq is a powerful command-line JSON processor that can merge JSON files:

# Merge two JSON files
jq -s '.[0] * .[1]' file1.json file2.json > merged.json

# Deep merge with custom array handling
jq -s '.[0] * .[1] | .array = (.[0].array + .[1].array)' file1.json file2.json > merged.json

Using Node.js

You can create a simple script to merge JSON files with Node.js:

const fs = require('fs');
const _ = require('lodash');

// Read JSON files
const file1 = JSON.parse(fs.readFileSync('file1.json', 'utf8'));
const file2 = JSON.parse(fs.readFileSync('file2.json', 'utf8'));

// Merge objects
const merged = _.merge({}, file1, file2);

// Write result
fs.writeFileSync('merged.json', JSON.stringify(merged, null, 2));

Best Practices for Merging JSON

  1. Be explicit about duplicate keys: Understand how your chosen method handles key conflicts
  2. Consider immutability: Create new objects rather than modifying existing ones
  3. Handle deep merging carefully: Use proper recursive methods or libraries for nested objects
  4. Validate the merged result: Ensure the final object has a valid structure
  5. Test with edge cases: Empty objects, null values, deeply nested structures
  6. Document your merge strategy: Make it clear how conflicts are resolved
  7. Consider performance: For large objects, some deep merge implementations might be inefficient

Conclusion

Merging JSON objects is a common but nuanced operation. The appropriate merging strategy depends on your specific requirements, data structure, and language environment. By understanding the various merging techniques and their implications, you can effectively combine data from different sources while maintaining data integrity and meeting your application's needs.

Author

avatar for Corey
Corey

Categories

Newsletter

Join the community

Subscribe to our newsletter for the latest news and updates