23

I've got an arbitrary structure with many levels, etc. I need to select all objects that contain a key named updateDate. How do I do that with jq? I came up with one way but it also produces errors on invalid data types when it visits a leaf which I have to grep out:

jq 'recurse(.[]) | has("updateDate")' | grep -Fv error

I don't really understand how to also check for types or leaves and I suspect there is a simpler way to achieve what I want?

user2259432
  • 2,239
  • 1
  • 19
  • 15
Yuri Geinish
  • 16,744
  • 6
  • 38
  • 40

3 Answers3

26

In 1.4 you can just:

jq '..|.updateDate?'

If you're stuck with 1.3 you can use a longer program like so:

jq 'recurse(if type == "array" or type = "object" then .[] else empty end) | if type == "object" then .updateDate else empty end'
user2259432
  • 2,239
  • 1
  • 19
  • 15
  • 2
    This will error out when the structure includes arrays. Adding `|objects|` in the middle fixes it, I think. – Tgr Sep 26 '17 at 00:27
  • Note if you want to filter empty arrays then you could follow https://stackoverflow.com/a/26196653/308851 `jq '..|.updateDate?|select(length>0)'` – chx Jun 12 '19 at 07:46
9

The accepted answer also produces null for every object that doesn't have the key.

What worked for me was:

jq '..|objects|.updateDate//empty'

The .updateDate//empty part means: if .updateDate is null (or false), skip it entirely.

This of course wouldn't work if you expect your key to have values of false or null. In that case, use this:

jq '..|objects|select(has("updateDate"))|.updateDate'
Juan Campa
  • 1,181
  • 2
  • 14
  • 20
1

Not tested: how about jq 'recurse(.[]?) | objects | has("updateDate")' ?

hobbs
  • 223,387
  • 19
  • 210
  • 288