PDFFlare
9 min read

How to Query JSON with JSONPath (Examples + Cheat Sheet)

You're staring at a 5,000-line JSON dump from an API. You need three specific fields buried in a deeply nested array of arrays. Writing a JS script to dig them out works, but takes longer than the actual analysis. JSONPath does it in one line — once you know the syntax.

In this guide you'll learn how to query JSON with JSONPath using PDFFlare's JSONPath Tester — the full syntax cheat sheet with worked examples, filter expressions with && / || / ! logic, and where JSONPath shines vs jq and JMESPath.

Why JSONPath?

JSONPath is to JSON what XPath is to XML — a small, declarative query language that pulls values out of structured data. It exists because the alternatives are painful:

  • Hand-writing JS: data.users.filter(u => u.active).map(u => u.email) works, but for one-off exploration it's a lot of typing.
  • jq:Powerful but a steeper learning curve, and it's a CLI tool. Browser-native JSONPath is faster for quick interactive work.
  • grep: Treats JSON as text. Misses nested matches, hits false positives, useless for structured queries.
  • Manual scrolling in a viewer: Fine for a 50-line JSON. Hopeless past that.

JSONPath Cheat Sheet

Most queries you'll ever write use only a handful of operators. Here's the lot:

  • $ — the root. Every expression starts here.
  • $.foo — the foo child of root.
  • $.foo.bar — chained children.
  • $['foo'] — bracket notation, equivalent to $.foo. Use brackets when keys contain dots or special characters.
  • $.foo[0] — first element of the foo array.
  • $.foo[*] — every element of the array (wildcard).
  • $.* — every value of the root object (wildcard).
  • $..key — recursive descent: every key anywhere in the tree, no matter how deep.
  • $.users[?(@.age > 30)] — filter expression: every user whose age > 30. The @means “the current item.”

Filter Expressions: The Real Power

Filters wrap a predicate in [?(...)]. Inside, use @ to refer to the current array item and access its fields with dot notation. Combine with logical operators for arbitrarily complex queries.

Comparators: == != < <= > >=.

Operands: field references (@.age), numbers (30), strings in single quotes ('admin'), booleans (true), null.

Logical operators: && (AND), || (OR), ! (NOT), with parentheses for grouping. Standard JS precedence: ! > && > ||.

Filter Examples

  • $.users[?(@.age > 30)] — users older than 30.
  • $.users[?(@.role == 'admin')] — admins only.
  • $.users[?(@.age > 30 && @.active == true)] — AND: active users older than 30.
  • $.users[?(@.role == 'admin' || @.tier > 2)] — OR: admins or high-tier users.
  • $.users[?(!(@.active))] — NOT: inactive users.
  • $.users[?(@.age > 30 && (@.role == 'admin' || @.tier > 2))] — grouped: older than 30, AND (admin OR high-tier).

Recursive Descent: $..key

Recursive descent finds every occurrence of a property name anywhere in the tree, no matter how deep. It's the killer feature for exploring unfamiliar JSON.

$..id on a nested API response with users, posts, and comments returns every id at every level — useful when you want a list of all unique IDs from a complex payload.

$..price in an e-commerce dataset gives you every price across products, variants, and bundles. One query, one answer.

How to Use JSONPath (Step by Step)

  1. Open PDFFlare's JSONPath Tester — no signup.
  2. Paste your JSON into the data pane (left).
  3. Type a JSONPath expression in the input box. Start simple: $.users[*].email if you have an array of users.
  4. Click Run (or press Enter). Matching values appear in the result pane on the right; the match-count banner shows the total.
  5. Iterate. Adjust the expression, re-run, refine. JSONPath is fast enough that exploration is interactive.

Common Mistakes

  • Forgetting the $. Every JSONPath expression starts with $. users[0].name without the dollar sign is invalid.
  • Double quotes around string operands. JSONPath literals use single quotes: ?(@.role == 'admin'), not ?(@.role == "admin"). The double quotes confuse the parser.
  • Comparing different types. @.age == '30'doesn't match an integer 30. JSONPath is type-strict — quote-types must agree.
  • Expecting wildcards in keys. $.user*doesn't mean “keys starting with user.” Use $.*for “every value of root,” or filter with ?(@.name =~ /pattern/) (if your implementation supports regex; PDFFlare does not yet).
  • Treating filter results as a single value. Filters always return an array of matches, even if there's only one. $.users[?(@.id == 1)] returns [user], not user.

Common Scenarios

Extracting Specific Fields From an API Response

You hit a paginated endpoint and want just the IDs from this page. $.data[*].id gives you a clean array of IDs. No scripting, no scrolling.

Debugging Deeply Nested Configs

A 200-level Helm chart values file (after converting via JSON to YAML back to JSON) has a setting buried six levels deep. $..containerPort finds every port across every container in every Deployment instantly.

Extracting Specific Order Items

An e-commerce JSON dump has thousands of orders. You want just completed orders over $1,000: $.orders[?(@.status == 'completed' && @.total > 1000)].

Audit Trails

A log dump has events at multiple levels. $..events[?(@.type == 'error')] gets every error event regardless of where it nests.

Pulling Test Data

You generated a fixture with PDFFlare's JSON Generator. Now you need just the email of every user under 25: $.users[?(@.age < 25)].email. One line.

JSONPath in Real Tools

JSONPath isn't just for browser-based exploration — many tools you already use support it natively:

  • kubectl: kubectl get pods -o jsonpath='{.items[*].metadata.name}' uses JSONPath to extract just the pod names from a full Pod list. Standard kubectl flag — every Kubernetes user has access to it.
  • Postman: Test scripts can use JSONPath via the pm.expect + JSONPath library to assert on specific fields without traversing the response tree by hand.
  • Splunk and CloudWatch Logs Insights: Both support JSONPath-like extraction from structured log fields. Same syntax, no learning curve.
  • Jolt (data transformation):JSONPath drives the “shift” operations that move fields between shapes during data transformation.
  • OpenAPI / JSON Schema: JSON Pointer (similar to JSONPath but stricter) is used for $ref. The mental model carries over.

Learning the syntax once unlocks all of these tools at the same time — that's a high-leverage skill for anyone who works with structured data day to day.

JSONPath Limitations Worth Knowing

The standard JSONPath subset is intentionally simple. A few things it can't do:

  • Aggregations:“Sum every price” or “count distinct values” — JSONPath doesn't aggregate. Reach for jq, JMESPath, or a real script.
  • Transformation: JSONPath is read-only. To reshape (rename, restructure, computed fields), you need a different tool.
  • Regex on values: RFC 9535 added a regex comparator (=~), but support varies. PDFFlare's current implementation doesn't include regex; for that, run JSONPath to a candidate set, then filter further in your code.
  • Computed paths:You can't do $.users[$.activeUserIndex]. Paths are static literals, not computed.
  • Custom functions: jq has a function library; JSONPath does not. Stay in JSONPath for ad-hoc queries, switch tools for transformation pipelines.

JSONPath vs jq vs JMESPath

  • JSONPath:Browser-native, zero install, simple syntax. Great for ad-hoc exploration. PDFFlare's tester implements the standard subset plus recursive descent and full filter expressions.
  • jq: Far more powerful — supports transformation, aggregation, custom functions. CLI tool. Better for scripting, worse for one-off browser queries.
  • JMESPath: Used heavily by AWS CLI. Different syntax. Powerful, but less ubiquitous than JSONPath. Worth learning if you live in AWS.

For interactive exploration, JSONPath wins on convenience. For pipelines and scripts, jq wins on power.

Building JSONPath Expressions Step by Step

When facing an unfamiliar JSON document, write the path incrementally rather than guessing the full expression at once:

  1. Start with $. Run it. The result pane shows the entire root document — confirms your JSON is valid and parseable.
  2. Add the first step. $.data or $.users — whatever the top-level container is. Run it. You should see the relevant sub-tree.
  3. Add a wildcard or index. If you got an array, try $.users[0] to see one element, or $.users[*] to see them all.
  4. Drill into the element. $.users[*].email or whatever field you need. Confirm the values match what you expect.
  5. Add filters last. Once the path is right, add the predicate: $.users[?(@.role == 'admin')].email.

This iterative approach is dramatically faster than writing a long expression and debugging it. Each step gives feedback that informs the next.

JSONPath Examples for Real API Shapes

A handful of expressions that come up over and over in real codebases:

  • $.data[*].id — every ID from a paginated list response.
  • $.data.items[?(@.deletedAt == null)] — every non-deleted item (soft-delete pattern).
  • $..errors[*].message — every error message from a deeply-nested validation response.
  • $.users[?(@.role == 'admin')].email — the email of every admin user.
  • $.transactions[?(@.amount > 1000 && @.currency == 'USD')] — high-value USD transactions only.
  • $.items[*].variants[?(@.inStock == true)] — every in-stock variant across every product.
  • $..[?(@.email)] — recursive descent for every object that has an email field, regardless of where it nests. Useful for scrubbing PII.

Save the patterns you use most often as a personal cheat sheet. Most queries you write will be variations of these basic shapes.

Best Practices

  • Format your JSON before querying. Run through PDFFlare's JSON Formatter first — visually scanning the structure helps you write the right path on the first try.
  • Start simple, add filters incrementally. Get the broad selection working, then narrow with predicates. Way faster to debug.
  • Use recursive descent sparingly. $..foo is convenient but slow on huge documents. Prefer explicit paths when you know the structure.
  • Quote keys with special characters. Keys containing dots, dashes, or spaces need bracket notation: $['weird-key'].
  • JSONPath is read-only. Use it to query, not modify. For modifications, write a script.

Privacy: Your JSON Stays on Your Device

PDFFlare's JSONPath Tester runs entirely in your browser. The parser, evaluator, and result rendering are JavaScript executed locally — your JSON never uploads anywhere. Safe to query production API responses, internal datasets, and JSON containing API tokens or PII.

Wrapping Up

A few hours learning JSONPath pays back forever. Once you're fluent, exploring an unfamiliar JSON dataset goes from a 30-minute scripting task to a 30-second query. The cheat sheet above covers 90% of what you'll write; the rest comes with practice.

Got JSON to query? Open PDFFlare's JSONPath Tester and try a few of the examples above.

Related Tools

  • JSON Formatter — pretty-print before querying for easier path-writing
  • JSON Viewer — inspect the tree visually to write the right path
  • JSON Stats — see depth + key counts before crafting queries
  • JSON Flatten — flatten to dot keys when JSONPath isn't enough