Merge two JSON objects with jq

Viewed 1202

I have the following two json files and I am trying to merge the DEV object.

jsonFile1:

{
  "ENV": {
    "DEV": {},
    "ST": {
      "middleware": [],
      "system": [],
      "application": [],
      "utility": []
    },
    "ESIT": {
      "middleware": [],
      "system": [],
      "application": [],
      "utility": []
    }
  }
}

jsonFile2:

{
  "ENV": {
    "DEV": {
      "middleware": [],
      "system": [],
      "application": [
         {
          "artefact": "abc",
          "domain": "df",
          "hostname": "sfa"
        },
        {
          "artefact": "awe",
          "domain": "csd",
          "hostname": "wer"
        }
      ],
      "utility": []
    }
  }
}

Expected Resulting Json Fi:

{
  "ENV": {
    "DEV": {
      "middleware": [],
      "system": [],
      "application": [
         {
          "artefact": "abc",
          "domain": "df",
          "hostname": "sfa",
        },
        {
          "artefact": "awe",
          "domain": "csd",
          "hostname": "wer",
        }
      ],
      "utility": []
    },
    "ST": {
      "middleware": [],
      "system": [],
      "application": [],
      "utility": []
    },
    "ESIT": {
      "middleware": [],
      "system": [],
      "application": [],
      "utility": []
    }
  }
}

I have already tried:

jq -s '.ENV["DEV"][] * .ENV["DEV"][]' jsonFile1.json jsonFile2.json

However that raises the error 'Cannot index array with string "ENV"'. I can also delete the '"DEV": {}' object out of jsonFile1 if that makes the merging process any easier.

2 Answers

Since you want to modify and output the first file, let's use --slurpfile to read the second file into a variable $other. Then we can merge the second file in place with *=, which both merges and assigns:

$ jq --slurpfile other jsonFile2.json '.ENV.DEV *= $other[].ENV.DEV' jsonFile1.json
{
  "ENV": {
    "DEV": {
      "middleware": [],
      "system": [],
      "application": [
        {
          "artefact": "abc",
          "domain": "df",
          "hostname": "sfa"
        },
        {
          "artefact": "awe",
          "domain": "csd",
          "hostname": "wer"
        }
      ],
      "utility": []
    },
    "ST": {
      "middleware": [],
      "system": [],
      "application": [],
      "utility": []
    },
    "ESIT": {
      "middleware": [],
      "system": [],
      "application": [],
      "utility": []
    }
  }
}

You can use *= to merge or = to overwrite.

It looks as though you simply want to set .ENV.DEV in the first file to .ENV.DEV in the second. If so, then assuming the contents of the second file is somehow in the jq variable $f2, all you need is an assignment statement:

.ENV.DEV = $f2.ENV.DEV

So, if you don't mind using --argfile, you could write:

jq --argfile f2 jsonFile2.json '.ENV.DEV=$f2.ENV.DEV' jsonFile1.json

This at least gives the expected result (modulo some technical issues in the given sample).

Since --argfile is technically deprecated, you might wish to use --slurpfile instead, and I could imagine you might want to use +=, but unless you really know what using * or *= implies, I'd avoid them.

Related