TL;DR
$— Root element, always start here.propertyor['property']— Access object properties[0],[*],[0:5]— Array access..property— Recursive search (find anywhere)[?(@.price < 10)]— Filter expressions
What is JSONPath?
JSONPath is like XPath for JSON. It's a query language that lets you extract specific data from complex JSON structures using simple expressions.
Instead of writing nested loops and conditionals to find data, you write a path expression:
$.store.book[*].author // Get all authors
$.store.book[?(@.price < 10)] // Get books under $10 JSONPath is supported in many languages and tools — perfect for APIs, testing frameworks, and data processing pipelines.
Our Sample Data
We'll use this JSON for all examples:
{
"store": {
"name": "Book Haven",
"book": [
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"price": 8.99
},
{
"category": "fiction",
"author": "J.R.R. Tolkien",
"title": "The Lord of the Rings",
"price": 22.99
},
{
"category": "nonfiction",
"author": "Stephen Hawking",
"title": "A Brief History of Time",
"price": 14.99
}
],
"bicycle": {
"color": "red",
"price": 199.99
}
}
} Basic Syntax
Root Element ($)
Every JSONPath expression starts with $ — the root of the document:
$ // Returns the entire JSON document
$.store // Returns the store object
$.store.name // Returns "Book Haven" Dot Notation vs Bracket Notation
Two ways to access properties:
// Dot notation (cleaner)
$.store.book
// Bracket notation (required for special characters)
$['store']['book']
$['store-name'] // Use brackets for hyphens
$['my key'] // Use brackets for spaces Array Access
By Index
$.store.book[0] // First book
$.store.book[1] // Second book
$.store.book[-1] // Last book
$.store.book[-2] // Second to last All Elements
$.store.book[*] // All books
$.store.book[*].title // All book titles
// Returns: ["Moby Dick", "The Lord of the Rings", "A Brief History of Time"] Array Slices
$.store.book[0:2] // First two books (index 0 and 1)
$.store.book[1:] // All books except first
$.store.book[:2] // First two books
$.store.book[::2] // Every other book (step of 2) Multiple Indices
$.store.book[0,2] // First and third book
$.store.book[0,1].title // Titles of first two books Recursive Descent (..)
The .. operator searches recursively through all nested levels.
It's powerful but can be slow on large documents.
$..author // All authors anywhere in the document
// Returns: ["Herman Melville", "J.R.R. Tolkien", "Stephen Hawking"]
$..price // All prices (books AND bicycle)
// Returns: [8.99, 22.99, 14.99, 199.99]
$..title // All titles
// Returns: ["Moby Dick", "The Lord of the Rings", "A Brief History of Time"] Filter Expressions
Filters let you select elements that match a condition.
Use [?(...)] with @ representing the current element.
Comparison Operators
// Books cheaper than $15
$.store.book[?(@.price < 15)]
// Books exactly $22.99
$.store.book[?(@.price == 22.99)]
// Books not in fiction category
$.store.book[?(@.category != 'fiction')]
// Books between $10 and $20
$.store.book[?(@.price >= 10 && @.price <= 20)] String Matching
// Books by specific author
$.store.book[?(@.author == 'Herman Melville')]
// Books in fiction category
$.store.book[?(@.category == 'fiction')]
// Books with "The" in title (regex, if supported)
$.store.book[?(@.title =~ /The/)] Existence Checks
// Books that have an ISBN property
$.store.book[?(@.isbn)]
// Books without a discount property
$.store.book[?(!@.discount)] Common Patterns
Pattern 1: Extract All Values of a Key
// All names in the document
$..name
// All IDs in nested data
$..id
// All email addresses
$..email Pattern 2: Filter and Extract
// Get titles of cheap books
$.store.book[?(@.price < 10)].title
// Returns: ["Moby Dick"]
// Get authors of fiction books
$.store.book[?(@.category == 'fiction')].author
// Returns: ["Herman Melville", "J.R.R. Tolkien"] Pattern 3: Nested Array Access
// For this structure:
// { "orders": [{ "items": [{ "name": "A" }, { "name": "B" }] }] }
// Get all item names from all orders
$.orders[*].items[*].name Pattern 4: Conditional Selection
// Get first matching item
$.store.book[?(@.category == 'nonfiction')][0]
// Get count of items (if supported)
$.store.book.length Using JSONPath in JavaScript
Install the jsonpath-plus library:
npm install jsonpath-plus import { JSONPath } from 'jsonpath-plus';
const data = {
store: {
book: [
{ title: "Book A", price: 10 },
{ title: "Book B", price: 20 }
]
}
};
// Basic query
const titles = JSONPath({ path: '$.store.book[*].title', json: data });
console.log(titles); // ["Book A", "Book B"]
// Filter query
const cheapBooks = JSONPath({
path: '$.store.book[?(@.price < 15)]',
json: data
});
console.log(cheapBooks); // [{ title: "Book A", price: 10 }]
// Recursive search
const allPrices = JSONPath({ path: '$..price', json: data });
console.log(allPrices); // [10, 20] Using JSONPath in Python
pip install jsonpath-ng from jsonpath_ng import parse
from jsonpath_ng.ext import parse as parse_ext
data = {
"store": {
"book": [
{"title": "Book A", "price": 10},
{"title": "Book B", "price": 20}
]
}
}
# Basic query
expr = parse('$.store.book[*].title')
titles = [match.value for match in expr.find(data)]
print(titles) # ['Book A', 'Book B']
# With filter support (requires jsonpath-ng.ext)
expr = parse_ext('$.store.book[?price < 15]')
cheap_books = [match.value for match in expr.find(data)]
print(cheap_books) # [{'title': 'Book A', 'price': 10}] Command Line: jq Alternative
While JSONPath is great, jq is the go-to CLI tool for JSON processing.
It uses different syntax but similar concepts:
# jq uses . instead of $ for root
cat data.json | jq '.store.name'
# "Book Haven"
# Array access
cat data.json | jq '.store.book[0].title'
# "Moby Dick"
# Filter (jq syntax)
cat data.json | jq '.store.book[] | select(.price < 15)'
# Get all values of a key
cat data.json | jq '.. | .author? // empty' Quick Reference
| Expression | Description |
|---|---|
$ | Root object/element |
@ | Current object (in filters) |
.property | Child property |
['property'] | Child property (bracket notation) |
[n] | Array element by index |
[*] | All array elements |
[start:end] | Array slice |
[?(expr)] | Filter expression |
.. | Recursive descent |
==, !=, <, <=, >, >= | Comparison operators |
&&, || | Logical operators |
Best Practices
- Be specific —
$.users[0].nameis faster than$..name - Avoid deep recursion —
..scans everything; use sparingly - Test incrementally — Build complex queries step by step
- Handle missing data — Queries may return empty arrays
- Know your implementation — JSONPath syntax varies slightly between libraries
FAQ
Is JSONPath standardized?
Not officially. There's an IETF draft, but implementations vary. Always test with your specific library.
JSONPath vs jq?
JSONPath is simpler and works in more languages. jq is more powerful for transformations but is mainly a CLI tool.
Can JSONPath modify JSON?
Standard JSONPath is read-only (query only). Some libraries add mutation capabilities, but that's not standard.
Performance considerations?
Recursive descent (..) and complex filters can be slow on large documents.
Cache results when querying the same data multiple times.
Related Articles
- JSON Arrays and Objects — Understand the structures you're querying
- Working with JSON APIs — Apply JSONPath to API responses
- JSON Schema — Define expected data structures