$.store.book[[email protected] < 10] selects every book whose price is less than 10. [?…] is a filter selector (RFC 9535 section 2.3.5): it visits each element of the array, calls it @, and keeps the element when the expression is true. Add a member after the filter to take one field of each match instead of the whole object.
On the RFC’s bookstore, the document in the tester below:
$.store.book[[email protected] < 10].title
$['store']['book'][0]['title'] "Sayings of the Century"
$['store']['book'][2]['title'] "Moby Dick"
Strings, and, or
$.store.book[[email protected] == "fiction"].title Sword of Honour, Moby Dick, The Lord of the Rings
$.store.book[[email protected] == 'fiction' && @.price < 10].title Moby Dick
$.store.book[[email protected] < 9 || @.price > 20].title Sayings of the Century, Moby Dick, The Lord of the Rings
$.store.book[?!(@.price < 10)].title Sword of Honour, The Lord of the Rings
Strings take single or double quotes. && binds tighter than ||, so group with parentheses when you mean otherwise, and put ! in front of a parenthesized comparison: [[email protected] < 10] is an error.
Existence
$.store.book[[email protected]].title keeps the books that have an isbn member, whatever its value: Moby Dick and The Lord of the Rings. [[email protected]] keeps the other two.
Gotchas
- Missing isn’t
null.[[email protected] == null]selects nothing here. A member that isn’t there is Nothing, which equals only Nothing;== nullmatches a member whose value isnull. - Comparisons are typed.
@.price < "10"is false for every book, without an error.<and>order two numbers or two strings, nothing else. - Quote strings. In
@.category == fiction, the word reads as a function call, and the tester refusesfiction(). - One value per side.
@.tags[*] == "sale"is an error, because@.tags[*]can select many nodes. A nested filter asks whether any tag matches:[[email protected][?@ == "sale"]]. - A filter on an object tests its member values.
$.store[[email protected] < 500]selects the bicycle.
In older libraries and other tools
Libraries written before RFC 9535 want the filter in parentheses. $.store.book[?(@.price < 10)] is valid RFC 9535 too, where the parentheses only group, so it’s the spelling that works in each tool below, all run on the same bookstore:
- Jayway JsonPath 3.0.0 (Java) runs
[?(@.price < 10)]and throwsInvalidPathExceptionon[[email protected] < 10]. It adds=~ /regex/andin, and$.store[?(@.price < 500)]selects nothing there. - jsonpath-plus 11.1.0 (JavaScript) runs the parenthesized form and returns
[]for the bare one, with no error. Its filters are JavaScript, so@.isbn == nullmatches the two books without an ISBN, and@.price < "10"matches the two cheap ones. - kubectl 1.32 takes the parenthesized form only, and rejects
?@as an invalid array index:kubectl get pods -o jsonpath='{.items[?(@.status.phase=="Running")].metadata.name}'.
The same filter in jq and in JMESPath, the language of aws --query, where a number literal goes in backticks:
jq .store.book[] | select(.price < 10)
JMESPath store.book[?price < `10`]