JSONPath filter by value

$.store.book[[email protected] < 10]

$.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; == null matches a member whose value is null.
  • 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 refuses fiction().
  • 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 throws InvalidPathException on [[email protected] < 10]. It adds =~ /regex/ and in, 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 == null matches 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`]

Try it in the JSONPath Tester

Member names, wildcards, indexes, slices, descendants and filters, the way RFC 9535 defines them. match() and search() take I-Regexp patterns: . is any character but \n and \r, \p{Lu} is a Unicode category, and there are no \d classes, no backreferences and no anchors.

Selection

2 values selected

PathValue
$['store']['book'][0]{ "category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95 }
$['store']['book'][2]{ "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 }

The document, with the selection marked

{
  "store": {
    "book": [
      { "category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95 },
      { "category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99 },
      { "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 },
      { "category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99 }
    ],
    "bicycle": { "color": "red", "price": 399 }
  }
}

Runs in your browser. Nothing you enter is sent anywhere.