skip to Main Content

I’m trying to merge some json objects using jq.

It seems to complicated for me ^^

I have a json which looks like this

[
  {
    "name": "test_name",
    "cpu": "1",
    "ip": "192.168.0.1",
    "kv_key": "test2_key",
    "kv_value": "test2_value",
    "location": "here"
  },
  {
    "name": "test_name",
    "cpu": "1",
    "ip": "192.168.0.2",
    "kv_key": "test1_key",
    "kv_value": "test1_value",
    "location": "here"
  },
  {
    "name": "test_name",
    "cpu": "1",
    "ip": "192.168.0.1",
    "kv_key": "test2_key",
    "kv_value": "test2_value",
    "location": "here"
  },
  {
    "name": "test_name",
    "cpu": "1",
    "ip": "192.168.0.1",
    "kv_key": "test3_key",
    "kv_value": "test3_value",
    "location": "here"
  }
]

And I want something like this

[
  {
    "name": "test_name",
    "cpu": "1",
    "ip": [
        "192.168.0.1",
        "192.168.0.2"
    ],
    "key_value": [
        {
            "test1_key": "test1_value",
            "test2_key": "test2_value",
            "test3_key": "test3_value"
        }
    ],
    "location": "here"
  }
]

I managed to make something work for the ip field only

jq 'map(. |= (group_by(.name) | map(first + {ip: map(.ip)})))' <<< "${json}"

Probably not the best way to do this and I’m clearly stuck on the key/value part.

Thx for you help !

amans

2

Answers


  1. You can try:

    $ jq 'group_by(.name) | map(first + {ip: map(.ip) | unique} + {key: map(.kv_key) | unique} + {value: map(.kv_value) | unique}) | map(. + {key_value: [.key,.value] | transpose | map({(.[0]):.[1]}) | add}) | map(del(.key,.value,.kv_key,.kv_value))' file
    [
      {
        "name": "test_name",
        "cpu": "1",
        "ip": [
          "192.168.0.1",
          "192.168.0.2"
        ],
        "location": "here",
        "key_value": {
          "test1_key": "test1_value",
          "test2_key": "test2_value",
          "test3_key": "test3_value"
        }
      }
    ]
    
    Login or Signup to reply.
  2. If all items have the same keys, you can make this generic by using to_entries to split the objects into an array of key-value pairs, transpose them, and combine them again using from_entries. Duplicate values can be eliminated using unique, and singletons can be generated by checking for the presence of a second item using select(has(1)):

    group_by(.name) | map(map(to_entries) | transpose | map(
        first + {value: (map(.value) | unique | select(has(1)) // first)}
    ) | from_entries)
    
    [
      {
        "name": "test_name",
        "cpu": "1",
        "ip": [
          "192.168.0.1",
          "192.168.0.2"
        ],
        "kv_key": [
          "test1_key",
          "test2_key",
          "test3_key"
        ],
        "kv_value": [
          "test1_value",
          "test2_value",
          "test3_value"
        ],
        "location": "here"
      }
    ]
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search