Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merge Arrays of JSON

Tags:

json

arrays

bash

jq

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?

like image 792
Waffy Avatar asked Feb 02 '17 19:02

Waffy


People also ask

How do I combine two JSON arrays?

We can merge two JSON arrays using the addAll() method (inherited from interface java.

How do I merge two JSON objects?

JSONObject to merge two JSON objects in Java. We can merge two JSON objects using the putAll() method (inherited from interface java.

Can we merge two JSON files?

There are a couple of reasons to merge JSON files:To combine the information in two JSON files – simple JSON Data Merge. Because two files have been updated and you want to combine the changes.


3 Answers

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"
    }
  ]
}
like image 113
zeppelin Avatar answered Oct 11 '22 05:10

zeppelin


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.

like image 37
Jannis Ioannou Avatar answered Oct 11 '22 04:10

Jannis Ioannou


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.

like image 28
Jeff Mercado Avatar answered Oct 11 '22 06:10

Jeff Mercado