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.