In more detail
$ is the root, .key steps into a field, [*] takes every element, [?(@.price < 10)] filters and .. searches at any depth. $.store.book[*].title returns every book title. Array positions start at 0, and a negative index such as [-1] counts from the end. It is standardised as RFC 9535, which also writes filters without the parentheses ([[email protected] < 10]). See How JSON Works.
Why it matters
JSONPath lets you pull a few values out of a large API response or configuration file without writing a loop, and the same expression can be pasted into tests, log pipelines and tools. The catch is that implementations written before the standard disagree on details such as filter syntax, how a missing field behaves and whether results come back as a list. Test an expression against the exact library you will use.
Example
Given this document:
{"store": {"book": [
{"title": "A", "price": 8.95},
{"title": "B", "price": 12.99},
{"title": "C", "price": 8.99}],
"bicycle": {"color": "red", "price": 19.95}}}
$.store.book[0].title returns "A". $.store.book[?(@.price < 10)].title returns "A" and "C", the two books under 10. $..price returns all four prices: 8.95, 12.99, 8.99 and 19.95. Try your own expressions in the JSONPath Tester, or browse the structure first with the JSON Viewer.
Common confusion
JSONPath is not jq, which has its own, different language for filtering and transforming JSON. It is only a path language that selects values; it does not change them.