jsonjqobject-construction

Reconstructing JSON with jq


I have a JSON like this (sample.json):

{
  "sheet1": [
    {
      "hostname": "sv001",
      "role": "web",
      "ip1": "172.17.0.3"
    },
    {
      "hostname": "sv002",
      "role": "web",
      "ip1": "172.17.0.4"
    },
    {
      "hostname": "sv003",
      "role": "db",
      "ip1": "172.17.0.5",
      "ip2": "172.18.0.5"
    }
  ],
  "sheet2": [
    {
      "hostname": "sv004",
      "role": "web",
      "ip1": "172.17.0.6"
    },
    {
      "hostname": "sv005",
      "role": "db",
      "ip1": "172.17.0.7"
    },
    {
      "hostname": "vsv006",
      "role": "db",
      "ip1": "172.17.0.8"
    }
  ],
  "sheet3": []
}

I want to extract data like this:

sheet1

jq '(something command)' sample.json

{
    "web": {
        "hosts": [
            "172.17.0.3",
            "172.17.0.4"
        ]
    },
    "db": {
        "hosts": [
            "172.17.0.5"
        ]
    }
}

Is it possible to perform the reconstruction with jq map? (I will reuse the result for ansible inventory.)


Solution

  • Here's a short, straight-forward and efficient solution -- efficient in part because it avoids group_by by courtesy of the following generic helper function:

    def add_by(f;g): reduce .[] as $x ({}; .[$x|f] += [$x|g]);
    
    .sheet1
    | add_by(.role; .ip1) 
    | map_values( {hosts: .} )
    
    

    Output

    This produces the required output:

    {
     "web": {
        "hosts": [
          "172.17.0.3",
          "172.17.0.4"
        ]
      },
      "db": {
        "hosts": [
          "172.17.0.5"
        ]
      }
    }