Filtering

jq has(), contains() & test() (Key Exists, Substring, Regex)

3 min read

Three builtins answer “does this match?” — has for keys, contains for inclusion, test for regex.

has() — does a key/index exist?

[ { "name": "Ada", "email": "ada@x.io" }, { "name": "Mae" } ]
jq '[.[] | select(has("email"))]' data.json

Returns only the object with an email key. For arrays, has(2) checks index 2 exists.

contains() — is one value included in another?

contains works on strings, arrays and objects (deep):

jq '.[] | select(.name | contains("da"))' data.json     # substring match
jq 'select(.tags | contains(["dev"]))' obj.json          # array includes all of these
jq 'select(. | contains({user:{active:true}}))' obj.json # object sub-match

test() — regex match

[ { "name": "Ada" }, { "name": "Alan" }, { "name": "Mae" } ]
jq '[.[] | select(.name | test("^A"))]' data.json     # names starting with A

Case-insensitive with the "i" flag:

jq '.[] | select(.name | test("ada"; "i"))' data.json

Extract matches with capture / match

echo '"order-1234"' | jq 'capture("order-(?<id>[0-9]+)")'   # {"id":"1234"}

Negate any of them

jq '[.[] | select(has("email") | not)]' data.json     # objects WITHOUT email

Pick the right one: has = key presence; contains = “is X inside Y” (substring / subset / sub-object); test = regex boolean (match/capture extract the actual matched text). test needs Oniguruma regex support, included in standard jq builds.

Open the full version (with copy buttons) ↗

← All recipes