Home > Enterprise >  How to filter object at multiple levels in JQ?
How to filter object at multiple levels in JQ?

Time:09-09

I have a json like this but much longer:

[
  {
    "id": "123",
    "name": "home network configuration",
    "description": "home utilities",
    "definedRanges": [
      {
        "id": "6500b67e",
        "name": "100-200",
        "beginIPv4Address": "192.168.090.100",
        "endIPv4Address": "192.168.090.200",
        "state": "UNALLOCATED"
      }
    ]
  },
  {
    "id": "456",
    "name": "lab network configuration",
    "description": "lab experiments",
    "definedRanges": [
      {
        "id": "1209b90d",
        "name": "100-200",
        "beginIPv4Address": "192.168.090.100",
        "endIPv4Address": "192.168.090.200",
        "state": "ALLOCATED"
      },
      {
        "id": "99e08ca4",
        "name": "100-200",
        "beginIPv4Address": "192.168.090.100",
        "endIPv4Address": "192.168.090.200",
        "state": "UNALLOCATED"
      }
    ]
  }
]

I'd like to query with jq and obtain the following:

[
  {
    "name": "home network configuration"
    "definedRanges": [
      {
        "name": "100-200",
        "beginIPv4Address": "192.168.090.100",
        "endIPv4Address": "192.168.090.200",
      }
    ]
  },
  {
    "name": "lab network configuration",
    "definedRanges": [
      {
        "name": "100-200",
        "beginIPv4Address": "192.168.090.100",
        "endIPv4Address": "192.168.090.200",
      },
      {
        "name": "100-200",
        "beginIPv4Address": "192.168.090.100",
        "endIPv4Address": "192.168.090.200",
      }
    ]
  }
]

or even this:

[
  {
    "name": "home network configuration",
    "definedRanges.name": "100-200",
    "definedRanges.beginIPv4Address": "192.168.090.100",
    "definedRanges.endIPv4Address": "192.168.090.200",
  },
  {
    "name": "lab network configuration",
    "definedRanges.name": "100-200",
    "beginIPv4Address": "192.168.090.100",
    "endIPv4Address": "192.168.090.200",
  },
  {
    "name": "lab network configuration",
    "beginIPv4Address": "192.168.090.100",
    "endIPv4Address": "192.168.090.200",
  }
]

So far I was able to extract the network name at the first level with:

.[] | {name}

I could also extract the definedRanges with:

.[].definedRanges[] | {name,beginIPv4Address,endIPv4Address}

But I can't figure out how to merge the two with jq.

I solved the problem with a very simple python script (7 lines of code) but now I'd like to understand how to do the same with jq, out of curiosity.

CodePudding user response:

Well, you were close. Here's how you put those together:

map({name, definedRanges: .definedRanges | map({name, beginIPv4Address, endIPv4Address})})

Online demo

CodePudding user response:

The 'or even this' can be achieved using:

map(.name as $name | .definedRanges[] | { name, beginIPv4Address, endIPv4Address} | with_entries(.key = "definedRanges."   .key) | .name = $name)

Which yields:

[
  {
    "definedRanges.name": "100-200",
    "definedRanges.beginIPv4Address": "192.168.090.100",
    "definedRanges.endIPv4Address": "192.168.090.200",
    "name": "home network configuration"
  },
  {
    "definedRanges.name": "100-200",
    "definedRanges.beginIPv4Address": "192.168.090.100",
    "definedRanges.endIPv4Address": "192.168.090.200",
    "name": "lab network configuration"
  },
  {
    "definedRanges.name": "100-200",
    "definedRanges.beginIPv4Address": "192.168.090.100",
    "definedRanges.endIPv4Address": "192.168.090.200",
    "name": "lab network configuration"
  }
]

Demo

  • Related