mifogon
mifogon

Reputation: 27

Skip printing a field when it is empty in the resulting JSON

I have json:

    "spec": {
        "background": true,
        "failurePolicy": "Fail",
        "rules": [
            {
                "exclude": {
                    "resources": {}
                },
                "generate": {
                    "clone": {}
                },
                "match": {
                    "resources": {
                        "kinds": [
                            "networking.k8s.io/v1/NetworkPolicy"
                        ]
                    }
                },
                "mutate": {},
                "name": "validate-nodeport",
                "validate": {
                    "message": "Services of type NodePort are not allowed.",
                    "pattern": {
                        "spec": {
                            "type": "!NodePort"
                        }
                    }
                }
            }
        ],
        "validationFailureAction": "audit"
    },
    "status": {
        "ready": true
    }
}

I have jq command:

(.spec.rules[0].match.resources.kinds[] / "/")
| [select(.[1])[0] // null, select(.[2])[1] // null, last]
  as [$version,$group,$kind]
| {$version,$group,$kind}

But sometimes field "version" or "group" maybe empty. I need to write with the following condition - if the string is null, then it is not necessary to write it.

Upvotes: 0

Views: 940

Answers (3)

pmf
pmf

Reputation: 36646

The {$version,$group,$kind} part from my other answer was included to show how to make use of the variables you requested to be created. Thus, if you don't want it to be written, don't generate it in the first place only to modify it later with with_entries(select(.value)) or the like. Instead, generate it differently, according to your needs.

For instance, instead of unconditionally using all three parts as in {$version,$group,$kind} you may pick just the ones that are not null using [{$version},{$group},{$kind} | select(.[])] | add: (Demo)

(.spec.rules[0].match.resources.kinds / "/")
| [select(.[1])[0] // null, select(.[2])[1] // null, last]
  as [$version,$group,$kind]
| [{$version},{$group},{$kind} | select(.[])] | add

Better yet, modify the [...] as {...} part directly to generate what you need, for instance: (Demo)

(.spec.rules[0].match.resources.kinds[] / "/")
| ({version:select(.[1])[0]} // {})
  + ({group:select(.[2])[1]} // {})
  + {kind: last}

Upvotes: 0

Arnaud Valmary
Arnaud Valmary

Reputation: 2325

Use select filter:

jq '(.spec.rules[0].match.resources.kinds[] / "/")
        | [select(.[1])[0] // null, select(.[2])[1] // null, last]
            as [$version,$group,$kind]
    | {$version,$group,$kind}
    | select(.version != "")
    | select(.group != "")
    ' \
    spec.json

Or if you want to only reduce output:

jq '(.spec.rules[0].match.resources.kinds[] / "/")
        | [select(.[1])[0] // null, select(.[2])[1] // null, last]
            as [$version,$group,$kind]
    | {$version,$group,$kind}
    | if .version != "" then
        if .group != "" then
            {$version,$group,$kind}
        else
            {$version,$kind}
        end
      else
        if .group != "" then
            {$group,$kind}
        else
            {$kind}
        end
      end
    ' \
    spec.json

Upvotes: 0

Inian
Inian

Reputation: 85895

The filter you have is already a pretty efficient way to deal with formation of objects, when all the individual fields (version, group and kind) are present and not required to re-write the whole thing to deal with one specific case.

To skip the null fields, just pipe your previous filter to below

with_entries(select(.value!=null))

i.e. the whole filter being below. See jqplay demo

(.spec.rules[0].match.resources.kinds[] / "/")
| [select(.[1])[0] // null, select(.[2])[1] // null, last]
  as [$version,$group,$kind]
| {$version,$group,$kind} 
| with_entries(select(.value!=null))

Upvotes: 2

Related Questions