How can I merge a sequence of objects with repeating keys into one?

Viewed 105

I have a sequence of objects, each with a single key. The values are themselves objects and the keys in the sequence may repeat. I would like to group said objects by their key and merge the values for repeated keys with something like jq's add.

More generally I want to

1. Group by key
2. Perform some op on array of values under matching keys
3. Get object with all unique keys from input with values the results of step 2

Here is my input:

# jq '.' /tmp/json.json 
{
  "cmsa-x-41100001": {
    "fqdn": "cmsa-x-41100001.example.com",
    "fqdn_ip4": [
      "100.64.40.10"
    ]
  }
}
{
  "cmsa-x-41100002": {
    "fqdn": "cmsa-x-41100002.example.com",
    "fqdn_ip4": [
      "100.64.40.5"
    ]
  }
}
{
  "cmsa-x-41100000": {
    "fqdn": "cmsa-x-41100000.example.com",
    "fqdn_ip4": [
      "100.64.40.13"
    ]
  }
}
{
  "cmsa-x-41100001": {
    "k8s_salt:cluster_domain": "cluster4.csip"
  }
}
{
  "cmsa-x-41100002": {
    "k8s_salt:cluster_domain": "cluster4.csip"
  }
}
{
  "cmsa-x-41100000": {
    "k8s_salt:cluster_domain": "cluster4.csip"
  }
}

Here is my desired output:

{
  "cmsa-x-41100000": {
    "fqdn": "cmsa-x-41100000.example.com",
    "fqdn_ip4": [
      "100.64.40.13"
    ],
    "k8s_salt:cluster_domain": "cluster4.csip"
  },
  "cmsa-x-41100001": {
    "fqdn": "cmsa-x-41100001.example.com",
    "fqdn_ip4": [
      "100.64.40.10"
    ],
    "k8s_salt:cluster_domain": "cluster4.csip"
  },
  "cmsa-x-41100002": {
    "fqdn": "cmsa-x-41100002.example.com",
    "fqdn_ip4": [
      "100.64.40.5"
    ],
    "k8s_salt:cluster_domain": "cluster4.csip"
  }
}

I have managed to achieve this with

jq -s 'map(to_entries[0]) | group_by(.key) | map(.[0].value = (map(.value) | add) ) | map(.[0]) | from_entries' /tmp/json.json

but it seems ugly and I feel, I'm doing it the wrong way. How would this be done properly?

1 Answers

Use reduce to fold all the objects together, and merge their contents with the * operator:

reduce .[] as $item ({}; . * $item)
Related