skipskap7
skipskap7

Reputation: 11

How can I use jq 'try-catch' inside of an object construction

The general problem statement is that I have some json data with fields that may or may not exist. Patterns like try .foo catch "bar" or .foo? // "bar" work just fine on their own, but not inside of an object construction cat myfile.json | jq -r '{foo: try .foo catch "bar"}'. Using an object construction is important for my use case, where I need to pass the same input through many filters and format the data nicely for later functions.

The data I'm working with is the output of kubectl get pods xxxxx -o json, and the part I'm trying to parse looks like this

{
  "items": [
    {
      "status": {
        "conditions": [
          {
            "type": "Initialized",
            "message": "foo"
          },
          {
            "type": "Ready"
          }
        ]
      }
    },
    {
      "status": {
      }
    }
  ]
}

For each item, if it has .status.conditions, I want the message from the first element in .status.conditions that has a message. The filter I used looks like this

jq -r '.items[] | {message: .status.conditions?|map(select(has("message")).message)[0]?}'

The problem is that when it gets to an item that doesn't have a .status.conditions, It returns the error Cannot iterate over null (null). This makes sense given that .status.conditions? passes null to the next filter, map which needs to iterate over a list. My attempted solution was to use various ways of try-catch to pass an empty list to map instead of null

jq -r '.items[] | {message: .status | try .conditions catch [] |map(select(has("message")).message)[0]?}'
jq -r '.items[] | {message: .status.conditions? // []|map(select(has("message")).message)[0]?}'

or to use a ? that includes the map call

jq -r '.items[] | {message: (.status.conditions?|map(select(has("message")).message)[0])?}'
jq -r '.items[] | {message: .status.conditions?|(map(select(has("message")).message)[0])?}'

All of these attempts return 1 compile error when written inside of an object constructor as shown, and work as expected when written on their own without an object constructor (e.g. '.items[] | .status.conditions?|(map(select(has("message")).message)[0])?')

The jq man page doesn't give any warnings (that I noticed) about how object construction changes the syntax requirements of what's inside, nor how try-catch can be affected by being inside an object construction. Any ideas?

Upvotes: 0

Views: 1060

Answers (1)

skipskap7
skipskap7

Reputation: 11

Thanks to @Fravadona, it was just a matter of parentheses. I had tried it at some point and made some mistake or other, but a working solution for my case is

jq -r '{message: .status | (.conditions? // []) | map(select(has("message")).message)[0]?}'

Upvotes: 1

Related Questions