JSONPath Cheat Sheet: Query Any JSON Document
JSONPath is a query language for JSON, analogous to XPath for XML. Given a deeply nested JSON document, a JSONPath expression lets you extract one value, a list of values, or everything that matches a pattern — without writing loops. It is supported natively in PostgreSQL (jsonb_path_query), AWS CloudFormation, Kubernetes admission webhooks, and most API testing tools.
Root and current node
| Symbol | Meaning |
|---|---|
$ | Root of the document |
@ | Current node (used inside filter expressions) |
Every JSONPath expression starts with $.
Navigation operators
| Operator | Meaning | Example |
|---|---|---|
.key | Child key (dot notation) | $.user.name |
["key"] | Child key (bracket notation — use for keys with spaces or special chars) | $["first name"] |
[n] | Array element at index n (0-based) | $.items[0] |
[*] | All array elements (wildcard) | $.items[*].id |
.* | All children of current node | $.user.* |
.. | Recursive descent — searches all depths | $..name |
Array slicing
JSONPath supports Python-style slice notation [start:end:step]:
| Expression | Result |
|---|---|
$.a[0:3] | Elements at index 0, 1, 2 |
$.a[-1] | Last element |
$.a[::2] | Every second element (0, 2, 4 …) |
$.a[1,3] | Elements at index 1 and 3 (union) |
Filter expressions
Filter expressions use ?(…) syntax to select elements that satisfy a condition. Inside the filter, @ refers to the current array element:
| Expression | Selects |
|---|---|
$.items[?(@.price < 10)] | Items where price is less than 10 |
$.users[?(@.active == true)] | Active users |
$..book[?(@.isbn)] | Any book with an isbn field |
$.orders[?(@.total >= 100 && @.status == "shipped")] | Shipped orders over $100 |
Practical examples
Given this document:
{
"store": {
"books": [
{ "title": "Clean Code", "price": 29.99, "inStock": true },
{ "title": "Refactoring", "price": 34.99, "inStock": false },
{ "title": "The Pragmatic Programmer", "price": 39.99, "inStock": true }
]
}
}| Expression | Result |
|---|---|
$.store.books[*].title | All three titles |
$.store.books[-1].title | "The Pragmatic Programmer" |
$.store.books[?(@.inStock)].title | "Clean Code", "The Pragmatic Programmer" |
$.store.books[?(@.price < 35)].title | "Clean Code", "Refactoring" |
$..price | All three prices (recursive) |
JSONPath in JavaScript
No native browser or Node.js API supports JSONPath — you need a library. The most widely used is jsonpath-plus:
import { JSONPath } from "jsonpath-plus";
const result = JSONPath({
path: "$.store.books[?(@.price < 35)].title",
json: document,
});
// ["Clean Code", "Refactoring"]JSONPath in PostgreSQL
PostgreSQL 12+ supports the SQL/JSON standard path language (similar to JSONPath) via jsonb_path_query:
SELECT jsonb_path_query(data, '$.store.books[*] ? (@.price < 35).title')
FROM products;Gotchas
- No universal standard — RFC 9535 (2024) finally standardised JSONPath, but many tools pre-date it and differ in filter syntax and recursion behaviour. Test your expressions against your specific library.
- Recursive descent is slow on large documents —
$..keytraverses the entire tree. Use specific paths in performance-sensitive code. - Missing nodes return an empty array, not null — account for this in your error handling.
Try it yourself
Use the free browser-based JSON Formatter & Validator on DevBench — no signup, runs entirely in your browser.
Open JSON Formatter & Validator