4

I have a JSON list which I want to merge on command line .

Input:
[
 {
   "ipaddress": "10.10.10.222",
   "name": "alice"
 },
 {
   "ipaddress": "10.20.20.77",
   "name": "bob"
 },
 {
   "version": "6.7",
   "name": "alice"
 },
 {
   "version": "5.2.2",
   "name": "bob"
 }
]

Expected Output:

{"name": "alice", "ipaddress": "10.10.10.222", "version": "6.7"},
{"name": "bob", "ipaddress": "10.20.20.77", "version": "5.2.2"}

can you help me? Thank you. bernd

Chris Stryczynski
  • 30,145
  • 48
  • 175
  • 286

2 Answers2

6
jq -c 'group_by(.name)[]|add' input.json

produces a stream of the JSON objects (i.e. without intervening commas).

Better yet would be to avoid group_by/1 altogether as it involves a sort:

def add_by(f):
  reduce .[] as $x ({}; ($x|f) as $f | .[$f] += [$x])
  | [.[] | add];

add_by(.name)
peak
  • 105,803
  • 17
  • 152
  • 177
  • Would you mind explaining how the reduce part works? I see what happens: it makes an object whose keys are "alice" and "bob" and the values of those keys are arrays filled with objects that have the corresponding .name value. But how does it select only the objects with "alice" to go with the "alice" key? That is eluding me. Thank you! – user197693 Sep 18 '17 at 17:30
  • @user197693 - The ’reduce' line groups the objects by .name; you can see this by adding 'debug' filters. – peak Sep 18 '17 at 19:04
  • I think I see it now. I didn't know about debug filters. Thanks. – user197693 Sep 18 '17 at 23:32
3

If the sample data is in data.json, the command

$ jq -Mr '[ group_by(.name)[] | add | tojson ] | join(",\n")' data.json

will produce the output

{"name": "alice", "ipaddress": "10.10.10.222", "version": "6.7"},
{"name": "bob", "ipaddress": "10.20.20.77", "version": "5.2.2"}

However if what is actually desired is a single array of objects then the command

$ jq -M '[group_by(.name)[] | add]' data.json

produces

[
  {
    "ipaddress": "10.10.10.222",
    "name": "alice",
    "version": "6.7"
  },
  {
    "ipaddress": "10.20.20.77",
    "name": "bob",
    "version": "5.2.2"
  }
]
jq170727
  • 13,159
  • 3
  • 46
  • 56
  • While this does answer the question, it is **not a general solution** for merging duplicates in an array. I added a sub array to each of the four elements ```codes: ["A", "B"]```, ```codes: ["C", "D", "E"]``` and so on. Each new ```codes``` attribute overwrites the previous ones. – Martin Bramwell Sep 16 '20 at 14:51