$..author selects every member named author, at any depth of the document. .. is the descendant segment (RFC 9535 section 2.5.2): it visits the node it starts from and every node below it, and applies the selector after it to each one. On the RFC’s bookstore, the document in the tester below, that’s the four book authors:
$['store']['book'][0]['author'] "Nigel Rees"
$['store']['book'][1]['author'] "Evelyn Waugh"
$['store']['book'][2]['author'] "Herman Melville"
$['store']['book'][3]['author'] "J. R. R. Tolkien"
The order of the results
RFC 9535 fixes two rules for the visit: a node comes before its descendants, and array elements come in array order. The order of an object’s members is left open, and the tester keeps them as written. The results are then joined in the order of the nodes they were found on, which isn’t always document order. $..[[email protected] > 20] gives the bicycle first and The Lord of the Rings second: the filter runs on store’s children, where the bicycle is, before it runs on the elements of book.
$..[[email protected] > 20]
$['store']['bicycle']
$['store']['book'][3]
$..* selects every member value and array element, 27 here. The root isn’t among them, since * selects children, and the rows come parent by parent: store, then book and bicycle, then the four books, then the members of each book and of the bicycle.
Gotchas
$..alone is an error. RFC 9535 says..isn’t a segment on its own: write$..*or$..[*], which mean the same.- Chaining multiplies.
$..*..authorselects 12 nodes, each author three times, because it starts a new descent fromstore, frombookand from each book. Use$..author, or$..book..authorto stay underbook. $..[0]is the first element of every array at any depth, not the first match.- It walks everything. On a large document, a full path such as
$.store.book[*].authorselects the same authors without visiting every node. - Finding where a value lives:
$..[?@ == "red"]names it:$['store']['bicycle']['color'].
In other tools
Jayway JsonPath 3.0.0 and jsonpath-plus 11.1.0 agree with the tester on $..author, $..price and $..*. Jayway lists $..[?(@.price > 20)] the other way round, The Lord of the Rings first. jsonpath-plus accepts a bare $.. and returns the root and each of its objects and arrays, eight nodes here; Jayway refuses it with Path must not end with a '.' or '..'.
jq’s .. recurses in the same order, a node before its children, but it yields every value, so pick the objects that have the member:
jq -c '[.. | objects | select(has("author")) | .author]' bookstore.json
# ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]
JMESPath has no recursive descent: store..price is a parse error, so every level has to be spelled out.