jsonshellcommand-linejq

How to merge 2 JSON objects from 2 files using jq?


I'm using the jq tools (jq-json-processor) in shell script to parse json.

I've got 2 json files and want to merge them into one unique file

Here the content of files:

file1

{
    "value1": 200,
    "timestamp": 1382461861,
    "value": {
        "aaa": {
            "value1": "v1",
            "value2": "v2"
        },
        "bbb": {
            "value1": "v1",
            "value2": "v2"
        },
        "ccc": {
            "value1": "v1",
            "value2": "v2"
        }
    }
}

file2

{
    "status": 200,
    "timestamp": 1382461861,
    "value": {
        "aaa": {
            "value3": "v3",
            "value4": 4
        },
        "bbb": {
            "value3": "v3"
        },      
        "ddd": {
            "value3": "v3",
            "value4": 4
        }
    }
}

expected result

{
    "value": {
        "aaa": {
            "value1": "v1",
            "value2": "v2",
            "value3": "v3",
            "value4": 4
        },
        "bbb": {
            "value1": "v1",
            "value2": "v2",
            "value3": "v3"
        },
        "ccc": {
            "value1": "v1",
            "value2": "v2"
        },
        "ddd": {
            "value3": "v3",
            "value4": 4
        }
    }
}

I try a lot of combinations but the only result i get is the following, which is not the expected result:

{
  "ccc": {
    "value2": "v2",
    "value1": "v1"
  },
  "bbb": {
    "value2": "v2",
    "value1": "v1"
  },
  "aaa": {
    "value2": "v2",
    "value1": "v1"
  }
}
{
  "ddd": {
    "value4": 4,
    "value3": "v3"
  },
  "bbb": {
    "value3": "v3"
  },
  "aaa": {
    "value4": 4,
    "value3": "v3"
  }
}

Using this command:

jq -s '.[].value' file1 file2

Solution

  • Since 1.4 this is now possible with the * operator. When given two objects, it will merge them recursively. For example,

    jq -s '.[0] * .[1]' file1 file2
    

    Important: Note the -s (--slurp) flag, which puts files in the same array.

    Would get you:

    {
      "value1": 200,
      "timestamp": 1382461861,
      "value": {
        "aaa": {
          "value1": "v1",
          "value2": "v2",
          "value3": "v3",
          "value4": 4
        },
        "bbb": {
          "value1": "v1",
          "value2": "v2",
          "value3": "v3"
        },
        "ccc": {
          "value1": "v1",
          "value2": "v2"
        },
        "ddd": {
          "value3": "v3",
          "value4": 4
        }
      },
      "status": 200
    }
    

    If you also want to get rid of the other keys (like your expected result), one way to do it is this:

    jq -s '.[0] * .[1] | {value: .value}' file1 file2
    

    Or the presumably somewhat more efficient (because it doesn't merge any other values):

    jq -s '.[0].value * .[1].value | {value: .}' file1 file2