DEV Community

kb7822836-hash
kb7822836-hash

Posted on

How to merge JSON files: JavaScript, Python and jq examples

Merging two JSON files sounds simple until the same key shows up in both. Do you keep the old value, the new one, or combine them? And what happens to arrays? This post shows the common options in JavaScript, Python and jq, and where each one breaks.

First decide what "merge" means

Take two small files:

// a.json
{ "user": { "name": "Ali", "age": 24 }, "tags": ["a", "b"] }

// b.json
{ "user": { "age": 25, "city": "Jhelum" }, "tags": ["b", "c"] }
Enter fullscreen mode Exit fullscreen mode

There are three questions to answer before you write any code:

  1. Shallow or deep? A shallow merge replaces the whole user object. A deep merge keeps name and combines the rest.
  2. Who wins a conflict? Usually the second file (age becomes 25).
  3. What happens to arrays? Join them, replace them, or join them without duplicates.

JavaScript

A shallow merge is one line, but it replaces nested objects completely:

const merged = { ...a, ...b };
// user becomes { age: 25, city: "Jhelum" }, and name is lost
Enter fullscreen mode Exit fullscreen mode

For a deep merge, write a small recursive function. Only plain objects are merged; everything else is replaced by the value from b:

const isPlainObject = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);

function deepMerge(a, b) {
  const out = { ...a };
  for (const key of Object.keys(b)) {
    if (isPlainObject(out[key]) && isPlainObject(b[key])) {
      out[key] = deepMerge(out[key], b[key]);
    } else {
      out[key] = b[key];
    }
  }
  return out;
}
Enter fullscreen mode Exit fullscreen mode

With this version, user is combined correctly, but tags is replaced by ["b","c"]. To join arrays instead, add one more branch:

if (Array.isArray(out[key]) && Array.isArray(b[key])) {
  out[key] = [...out[key], ...b[key]];            // join
  // out[key] = [...new Set([...out[key], ...b[key]])]; // join without duplicates (primitives only)
}
Enter fullscreen mode Exit fullscreen mode

The Set trick only removes duplicates for strings and numbers. For arrays of objects, compare JSON.stringify(item) instead.

Python

Python 3.9 and newer have a dict union operator, but it is also shallow:

import json

with open('a.json') as f1, open('b.json') as f2:
    a, b = json.load(f1), json.load(f2)

merged = a | b   # shallow: nested objects are replaced
Enter fullscreen mode Exit fullscreen mode

A deep merge is the same idea as in JavaScript:

def deep_merge(a, b):
    out = dict(a)
    for key, value in b.items():
        if isinstance(out.get(key), dict) and isinstance(value, dict):
            out[key] = deep_merge(out[key], value)
        else:
            out[key] = value
    return out
Enter fullscreen mode Exit fullscreen mode

To merge many files, fold them with functools.reduce(deep_merge, list_of_dicts).

jq on the command line

If you already work in a terminal, jq does this without any script. The * operator merges objects recursively, and the right side wins:

jq -s '.[0] * .[1]' a.json b.json
Enter fullscreen mode Exit fullscreen mode

Arrays are replaced, not joined. To merge more than two files:

jq -s 'reduce .[] as $x ({}; . * $x)' a.json b.json c.json
Enter fullscreen mode Exit fullscreen mode

Two files that are both top-level arrays can be joined with jq -s '.[0] + .[1]'.

When you just need the result

For a one-off merge you do not need to write or run anything. I built a free Merge JSON tool that merges two JSON files in the browser, so nothing is uploaded. It deep-merges objects, lets you choose how arrays are handled (standard, always join, or join without duplicates) and tells you how many values from the second file replaced a different value from the first. To see exactly what changed afterwards, compare the result with the original in the JSON Diff tool.

Common mistakes

  • Merging invalid JSON. A trailing comma or single quotes will stop the parser. Check each file with a JSON formatter and validator first.
  • Expecting arrays to merge by position. None of the examples above match array items by index. They join or replace whole arrays.
  • Order matters. The second file wins, so merge(a, b) and merge(b, a) can give different results.
  • Large files. Loading very big files into memory can be slow in a browser. Split them first, or use jq or Python.

Disclosure: I am the author of Parsekit.

Top comments (0)