Advanced 11 min read

JSONPath: Query Data Like a Pro

Extract exactly the data you need from complex JSON structures. Learn JSONPath expressions with practical examples and common patterns.

#jsonpath #queries #advanced #data-extraction

TL;DR

  • $ — Root element, always start here
  • .property or ['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:

example.txt
text
$.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.json
json
{
  "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:

root.txt
text
$                    // 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:

notation.txt
text
// 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

array-index.txt
text
$.store.book[0]           // First book
$.store.book[1]           // Second book
$.store.book[-1]          // Last book
$.store.book[-2]          // Second to last

All Elements

array-all.txt
text
$.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

array-slice.txt
text
$.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

array-multiple.txt
text
$.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.

recursive.txt
text
$..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

filters.txt
text
// 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

string-filters.txt
text
// 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

existence.txt
text
// 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

pattern-values.txt
text
// All names in the document
$..name

// All IDs in nested data
$..id

// All email addresses
$..email

Pattern 2: Filter and Extract

pattern-filter.txt
text
// 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

pattern-nested.txt
text
// For this structure:
// { "orders": [{ "items": [{ "name": "A" }, { "name": "B" }] }] }

// Get all item names from all orders
$.orders[*].items[*].name

Pattern 4: Conditional Selection

pattern-conditional.txt
text
// 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:

install.sh
bash
npm install jsonpath-plus
jsonpath-js.js
javascript
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

install-python.sh
bash
pip install jsonpath-ng
jsonpath-py.py
python
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-examples.sh
bash
# 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].name is 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
Try JSONPath queries! Use our JSON tools to explore and test JSONPath expressions on your data.

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.

About the Author

AT

Adam Tse

Founder & Lead Developer · 10+ years experience

Full-stack engineer with 10+ years of experience building developer tools and APIs. Previously worked on data infrastructure at scale, processing billions of JSON documents daily. Passionate about creating privacy-first tools that don't compromise on functionality.

JavaScript/TypeScript Web Performance Developer Tools Data Processing