Merge Arrays of JSON

29,766

Solution 1

You can merge your files with add (jq 1.3+):

jq -s '.[0].list=[.[].list|add]|.[0]' *.json

or flatten (jq 1.5+):

jq -s '.[0].list=([.[].list]|flatten)|.[0]' *.json

[.[].list] - creates an array of all "list" arrays

 [
  [
    {
      "name": "Ajay"
    }
  ],
  [
    {
      "name": "Al"
    }
  ]
]

[.[].list]|flatten - flatten it (or .[].list|add - add all the arrays together)

[
  {
    "name": "Ajay"
  },
  {
    "name": "Al"
  }
]

.[0].list=([.[].list]|flatten)|.[0] - replace the first "list" with the merged one, output it.

{
  "title": "NamesBook",
  "list": [
    {
      "name": "Ajay"
    },
    {
      "name": "Al"
    }
  ]
}

Solution 2

Let me also provide just what the title asks for, because I'm sure a lot of people that stepped on this question look for something simpler.

Any of the following (added math2001 and pmf answers):

echo -e '["a","b"]\n["c","d"]' | jq -s 'add'
echo -e '["a","b"]\n["c","d"]' | jq -s 'flatten(1)'
echo -e '["a","b"]\n["c","d"]' | jq -s 'map(.[])'
echo -e '["a","b"]\n["c","d"]' | jq -s '[.[][]]'
echo -e '["a","b"]\n["c","d"]' | jq '.[]' | jq -s

results in:

[
"a",
"b",
"c",
"d"
]

Note: Also any of the above can apply to arrays of objects.

Solution 3

Assuming every file will have the same title and you're simply combining the list contents, you could do this:

$ jq 'reduce inputs as $i (.; .list += $i.list)' blahblah.json blueblue.json

This just takes the first item and adds to its list, the list of all the other inputs.

Solution 4

The OP did not specify what should happen if there are objects for which .title is not "NamesBook". If the intent is to select objects with .title equal to "NamesBook", one could write:

map(select(.title == "NamesBook"))
| {title: .[0].title, list: map( .list ) | add}

This assumes that jq is invoked with the -s option.

Incidentally, add is the way to go here: simple and fast.

Share:
29,766

Related videos on Youtube

Waffy
Author by

Waffy

Updated on January 20, 2022

Comments

  • Waffy
    Waffy over 2 years

    So my objective is to merge json files obtain this format:

    {
      "title": "NamesBook",
      "list": [
        {
          "name": "Ajay"
        },
        {
          "name": "Al"
        }
      ]
    }
    

    And I have files that look like this format:

    blahblah.json

    {
      "title": "NamesBook",
      "list": [
        {
          "name": "Ajay"
        }
      ]
    }
    

    blueblue.json

    {
      "title": "NamesBook",
      "list": [
        {
          "name": "Al"
        }
      ]
    }
    

    I can store the list array of all my names in a variable with the following:

    x = jq -s '.[].list' *.json
    

    And then I was planning on appending the variable to an empty array in a file I created, out.json, which looks like this:

    {
      "type": "NamesBook",
      "list": []
    }
    

    However, when my script runs over the line

    jq '.list[] += "$x"' out.json'
    

    It brings up a jq error:

    Cannot iterate over null.

    Even when I add a random element, the same error shows up. Tips on how I should proceed? Are there other tools in jq to help achieve merging arrays?

  • Urosh T.
    Urosh T. over 2 years
    Worked like a charm for merging arrays! Thanks!
  • math2001
    math2001 over 2 years
    arguably simpler is jq -s 'flatten(1)'
  • pmf
    pmf over 2 years
    Or jq -s 'map(.[])' or even jq -s '[.[][]]' but jq -s 'add' is the simplest.