Search code examples
jsonselectjq

Select one of several subattributes dependent on its content


I have a JSON Output describing the configuration of an OPNSense Firewall.

I want to condense the output into something more useful. Consider the following element of a list of VLANs

[
  {
    "key": "0eb660b0-555a-469e-be04-8c3584108f9b",
    "value": {
      "if": {
        "igb1": {
          "value": "igb1 (64:62:66:22:6e:d0) [UNTAGGED]",
          "selected": 0
        },
        "igb2": {
          "value": "igb2 (64:62:66:22:6e:d1) [tagged]",
          "selected": 1
        }
      },
      "tag": "20",
      "pcp": {
        "1": {
          "value": "Background (1, lowest)",
          "selected": 0
        },
        "0": {
          "value": "Best Effort (0, default)",
          "selected": 1
        },
        "2": {
          "value": "Excellent Effort (2)",
          "selected": 0
        }
      },
      "proto": {
        "": {
          "value": "Auto",
          "selected": 1
        },
        "802.1q": {
          "value": "802.1Q",
          "selected": 0
        },
        "802.1ad": {
          "value": "802.1ad",
          "selected": 0
        }
      },
      "descr": "USERS: PCs und Handies  ",
      "vlanif": "vlan0.20"
    }
  }
]

I would like to see only the content for if, pcp or proto, which have selected ==1. Whether I get their key or their value is anther problem. The result could look like this:

[
  {
    "key": "0eb660b0-555a-469e-be04-8c3584108f9b",
    "value": {
      "if": {
        "igb2": {
          "value": "igb2 (64:62:66:22:6e:d1) [tagged]",
          "selected": 1
        }
      },
      "tag": "20",
      "pcp": {
        "0": {
          "value": "Best Effort (0, default)",
          "selected": 1
        }
      },
      "proto": {
        "": {
          "value": "Auto",
          "selected": 1
        }
      },
      "descr": "USERS: PCs und Handies  ",
      "vlanif": "vlan0.20"
    }
  }
]

See online

I tried all variants of select which occured to me. But i don't know how to select a subattribute and not the whole object.


Solution

  • Traverse to each potential object, e.g. using .[].value["if", "pcp", "proto"], and update its items using either map_values or another level of iteration (reliable since jq 1.7) by filtering for their items that match the condition, .selected == 1 in this case:

    .[].value["if", "pcp", "proto"] |= map_values(select(.selected == 1))
    # or
    .[].value["if", "pcp", "proto"][] |= select(.selected == 1)
    
    [
      {
        "key": "0eb660b0-555a-469e-be04-8c3584108f9b",
        "value": {
          "if": {
            "igb2": {
              "value": "igb2 (64:62:66:22:6e:d1) [tagged]",
              "selected": 1
            }
          },
          "tag": "20",
          "pcp": {
            "0": {
              "value": "Best Effort (0, default)",
              "selected": 1
            }
          },
          "proto": {
            "": {
              "value": "Auto",
              "selected": 1
            }
          },
          "descr": "USERS: PCs und Handies  ",
          "vlanif": "vlan0.20"
        }
      }
    ]
    

    Demo 1, Demo 2