JQ – How to Merge Arrays from Multiple JSON Files

jqjsonlinux

I have two JSON files (file1.json and file2.json) with the following same structure as defined below with two array lists as shown below.

The first file is (file1.json):

{
  "Lists1": [
   {
      "point": "a",
      "coordinates": [
        2289.48096,
        2093.48096
      ]
   }
  ],
  "Lists2": [
   {
      "point": "b",
      "coordinates": [
        2289.48096,
        2093.48096
      ]
   }
 ]
}

The second file is (file2.json):

{
  "Lists1": [
   {
      "point": "c",
      "coordinates": [
        2289.48096,
        2093.48096
      ]
   }
  ],
  "Lists2": [
   {
      "point": "d",
      "coordinates": [
        2289.48096,
        2093.48096
      ]
   }
 ]
}

so my expected output will be:

{
  "Lists1": [
   {
      "point": "a",
      "coordinates": [
        2289.48096,
        2093.48096
      ]
   },
   {
      "point": "c",
      "coordinates": [
        2289.48096,
        2093.48096
      ]
   }
  ]
  "Lists2": [
   {
      "point": "b",
      "coordinates": [
        2289.48096,
        2093.48096
      ]
   },
   {
      "point": "d",
      "coordinates": [
        2289.48096,
        2093.48096
      ]
   }
 ]
}

I am trying to merge (combine) these two files using jq. I found using the command below, but this only work with one list.

jq -n '{ list1: [ inputs.list1 ] | add }' file1.json file2.json

Is there a way to modify this function to combine both list1 and list2?

Best Answer

Assuming the top-most keys of all documents are always the same across all documents, extract the keys into a separate variable, then reduce (accumulate) the data over these keys.

jq -s '
    (.[0] | keys[]) as $k |
    reduce .[] as $item (null; .[$k] += $item[$k])' file*.json

Note the use of -s to read all the input into a single array.

This, more or less, iterates over the keys Lists1 and Lists2 for each document, accumulating the data in a new structure (null from the start).

Assuming that the input JSON documents are well-formed:

{
"Lists1": [{"point":"a","coordinates":[2289.48096,2093.48096]}],
"Lists2": [{"point":"b","coordinates":[2289.48096,2093.48096]}]
}
{
"Lists1": [{"point":"c","coordinates":[2289.48096,2093.48096]}],
"Lists2": [{"point":"d","coordinates":[2289.48096,2093.48096]}]
}

You will get the following resulting document containing two objects:

{
"Lists1": [{"point":"a","coordinates":[2289.48096,2093.48096]},{"point":"c","coordinates":[2289.48096,2093.48096]}]
}
{
"Lists2": [{"point":"b","coordinates":[2289.48096,2093.48096]},{"point":"d","coordinates":[2289.48096,2093.48096]}]
}

Would you want the two keys in the same object:

jq -s '
    [ (.[0] | keys[]) as $k |
      reduce .[] as $item (null; .[$k] += $item[$k]) ] | add' file*.json
Related Question