How to Query Nested JSON with JSONPath (Without Writing Loops)
Source: Dev.to
Introduction
You just got back a 300‑line API response. Somewhere inside three levels of nesting is the email field you actually need. Writing nested loops quickly becomes brittle when the API schema shifts.
JSONPath offers a concise, read‑only query language for JSON, similar to XPath for XML. Once you learn the syntax, you’ll reach for it constantly.
Example API response
{
"store": {
"orders": [
{
"id": 1,
"customer": { "name": "Alice", "email": "alice@example.com" },
"items": [{ "sku": "A1", "qty": 2 }, { "sku": "B3", "qty": 1 }]
},
{
"id": 2,
"customer": { "name": "Bob", "email": "bob@example.com" },
"items": [{ "sku": "C7", "qty": 5 }]
}
]
}
}
Getting every customer email
JSONPath expression
$.store.orders[*].customer.email
Result
["alice@example.com", "bob@example.com"]
$– root element.– navigate into an object key[*]– all array elements
Filtering by a condition
To retrieve only items where qty is greater than 1:
Expression
$.store.orders[*].items[?(@.qty > 1)]
Result
[
{ "sku": "A1", "qty": 2 },
{ "sku": "C7", "qty": 5 }
]
?()– filter expression@– current node
Comparison with explicit loops (Python)
# Without JSONPath — five lines, easy to get wrong
results = []
for order in data["store"]["orders"]:
for item in order["items"]:
if item["qty"] > 1:
results.append(item)
The JSONPath version is a single, self‑documenting line.
Recursive descent
When you don’t know the exact location of a key, use the recursive descent operator ..:
$..email
This finds every email field at any depth in the document—handy for exploring unfamiliar schemas.
Practical three‑step workflow
- Beautify – Paste the response into a JSON Beautifier to get a clean, indented view.
- Validate – Run it through a JSON Validator to ensure it’s well‑formed (malformed payloads return empty results).
- Query – Use a JSONPath tool (e.g., the JSONPath Evaluator on jsonindenter.com) to iterate on your expression until you extract exactly what you need.
JSONPath syntax cheat sheet
| Symbol | Meaning |
|---|---|
$ | Root element |
.key | Child key |
..key | Recursive search for key at any depth |
[*] | All array elements |
[0] | First element ([-1] – last element) |
[0,2] | Elements at index 0 and 2 |
[?(@.price < 10)] | Filter where price is less than 10 |
@.key | Current node’s key (inside filter expressions) |
Implementation notes
- Python –
jsonpath-ng - JavaScript –
jsonpath-plus - Java – Jayway JSONPath
Implementations differ slightly. RFC 9535 (published 2024) is working toward standardization, but for production code you should test expressions against the specific library you use.
When to use JSONPath vs. JSON Patch
JSONPath is read‑only: it queries and extracts data.
If you need to modify a JSON document (add, replace, or remove fields), use JSON Patch (RFC 6902). The two tools complement each other: JSONPath to find, JSON Patch to modify.
Conclusion
JSONPath makes complex JSON queries composable and readable. A well‑written expression communicates intent at a glance, while nested loops force the reader to work through the entire block before understanding the extraction. Because the same expression works across JavaScript, Python, Java, and tools like Postman, learning JSONPath pays off across your entire stack.
Free tools referenced
- JSONPath Evaluator – test JSONPath expressions live in the browser.
- JSON Beautifier – format raw JSON for easy reading.
- JSON Validator – verify that JSON is well‑formed before querying.
- JSON Patch – apply RFC 6902 patches to modify JSON structures in place.