How to test JSONPath expressions online
jsonsql.dev evaluates JSONPath expressions instantly in your browser. No data is sent to any server — your JSON stays on your machine.
Paste your JSON — copy JSON from your API response, config file, or database export and paste it into the input editor. You can also drag-and-drop a .json file.
Write a JSONPath expression — type your JSONPath query in the expression bar (e.g., $.store.books[*].title). Use the quick-insert buttons for common patterns.
View results — click Run or press Ctrl+Enter. Matching values appear as syntax-highlighted JSON in the results panel. Copy results with one click.
JSONPath syntax reference
JSONPath is to JSON what XPath is to XML — a query language for extracting data from structured documents using path expressions.
| Syntax | Description | Example | Result |
|---|---|---|---|
$ |
Root element | $ |
The entire JSON document |
.key |
Child access (dot notation) | $.store.bicycle |
{"color":"red","price":199.95} |
['key'] |
Child access (bracket notation) | $['store']['bicycle'] |
Same as dot notation |
[n] |
Array index (0-based, negative for end) | $.store.books[0] |
First book object |
[*] |
Wildcard — all children | $.store.books[*].title |
All book titles as an array |
.. |
Recursive descent (deep scan) | $..price |
All "price" values at any depth |
[start:end] |
Array slice | $.store.books[0:2] |
First two books |
[?(expr)] |
Filter expression | $.store.books[?(@.price < 15)] |
Books cheaper than $15 |
JSONPath dot notation vs bracket notation
Use dot notation ($.store.name) for simple keys and bracket notation ($['store']['my key']) when property names contain spaces or special characters.
When to use dot notation
- Simple alphanumeric property names:
$.user.name - Chaining multiple levels:
$.config.database.host - Combined with array access:
$.users[0].email
When to use bracket notation
- Keys with spaces:
$['first name'] - Keys with special characters:
$['content-type'] - Keys that look like numbers:
$['404'] - Dynamic or computed keys in code
Side-by-side comparison
// These expressions are equivalent:
$.store.books[0].title
$['store']['books'][0]['title']
// Bracket notation is required for special keys:
$['first name'] // space in key
$['content-type'] // hyphen in key
$['@attributes']['id'] // @ in key
// Dot notation is shorter and more readable:
$.store.bicycle.color // preferred
$['store']['bicycle']['color'] // equivalent but verbose
JSONPath filter expressions
JSONPath filter expressions use the syntax [?(@.field op value)] where @ refers to the current element being evaluated.
Numeric comparison
// Input
{
"products": [
{ "name": "Widget", "price": 25 },
{ "name": "Gadget", "price": 75 },
{ "name": "Gizmo", "price": 150 }
]
}
// Filter products cheaper than $100
$.products[?(@.price < 100)]
→ [{"name":"Widget","price":25}, {"name":"Gadget","price":75}]
// Filter products $75 or more
$.products[?(@.price >= 75)]
→ [{"name":"Gadget","price":75}, {"name":"Gizmo","price":150}]
String comparison
// Filter by exact string match
$.store.books[?(@.category == "fiction")]
→ Books in the fiction category
// Filter by not equal
$.store.books[?(@.category != "programming")]
→ Books NOT in the programming category
Existence check
// Filter elements that have an "email" field
$.users[?(@.email)]
→ Only users that have an email property
Supported operators
==— equal to (strings and numbers)!=— not equal to>— greater than<— less than>=— greater than or equal<=— less than or equal@.field(no operator) — existence check
JSONPath wildcard and recursive descent
Wildcards and recursive descent are the most powerful JSONPath features for searching across complex, deeply nested JSON structures.
Wildcard ([*])
The wildcard [*] matches all elements at the current level:
// Get all elements of an array
$[*] → all top-level elements
// Get a field from every array element
$.store.books[*].title → ["The Great Gatsby", "Clean Code", "Design Patterns", "1984"]
// Get all values of an object
$.store.* → [books_array, bicycle_object]
Recursive descent (..)
The recursive descent operator .. searches for a key at any depth in the JSON tree:
// Find ALL "price" values anywhere in the document
$..price
→ [12.99, 33.49, 41.99, 9.99, 199.95]
// Find all prices under "store" only
$.store..price
→ [12.99, 33.49, 41.99, 9.99, 199.95]
// Find all "title" values anywhere
$..title
→ ["The Great Gatsby", "Clean Code", "Design Patterns", "1984"]
Practical use cases
- API response extraction —
$..idcollects all IDs from a nested API response without knowing the exact structure. - Config file search —
$..hostfinds all host configurations across multiple environments. - Data validation —
$..emailextracts all email fields to check for valid formats. - Error log parsing —
$..errorfinds all error messages in a structured log.
JSONPath vs jq vs SQL for querying JSON
Different tools for different needs. Here is how JSONPath compares to jq and SQL for common JSON querying tasks.
| Aspect | JSONPath | jq | SQL (on JSON) |
|---|---|---|---|
| Syntax complexity | Low — dot/bracket notation | Medium — pipe-based functional | Low — familiar SELECT/WHERE |
| Installation required | No (browser-based here) | Yes (CLI tool) | No (browser-based here) |
| Browser-based | Yes (jsonsql.dev) | No | Yes (jsonsql.dev) |
| Deep nested access | Best ($.a.b.c) |
Good (.a.b.c) |
Limited |
| Recursive search | Yes ($..key) |
Yes (.. | .key?) |
No |
| Filter capability | Basic ([?(@.x>5)]) |
Full (select()) |
Full (WHERE clause) |
| Aggregation | No | Yes (length, add, etc.) | Yes (COUNT, SUM, AVG) |
| Learning curve | Very low | Steep | Low (if you know SQL) |
Same query in all three syntaxes
// Task: Get titles of books cheaper than $15
// JSONPath
$.store.books[?(@.price < 15)].title
// jq
.store.books[] | select(.price < 15) | .title
// SQL (jsonsql.dev SQL mode)
SELECT title FROM store.books WHERE price < 15
Try the SQL query mode or MongoDB query mode on jsonsql.dev for more advanced querying.
JSONPath in different languages
JSONPath is supported across all major programming languages. Here are code snippets showing how to evaluate JSONPath expressions in each.
JavaScript (jsonpath-plus)
import { JSONPath } from 'jsonpath-plus';
const data = { store: { books: [{ title: 'Gatsby', price: 12.99 }] } };
const result = JSONPath({ path: '$.store.books[*].title', json: data });
console.log(result); // ["Gatsby"]
Python (jsonpath-ng)
from jsonpath_ng.ext import parse
data = {"store": {"books": [{"title": "Gatsby", "price": 12.99}]}}
expr = parse("$.store.books[*].title")
result = [m.value for m in expr.find(data)]
print(result) # ["Gatsby"]
Java (Jayway JsonPath)
import com.jayway.jsonpath.JsonPath;
String json = "{\"store\":{\"books\":[{\"title\":\"Gatsby\"}]}}";
List<String> titles = JsonPath.read(json, "$.store.books[*].title");
System.out.println(titles); // ["Gatsby"]
Command line (jq equivalent)
# jq uses a different syntax but achieves the same result
cat data.json | jq '.store.books[].title'
# Output: "Gatsby"
# For JSONPath-compatible CLI, use jsonpath-cli (Node.js):
npx jsonpath-cli '$.store.books[*].title' data.json
Related tools
Frequently asked questions
What is the difference between dot notation and bracket notation in JSONPath?
Dot notation ($.store.name) is shorter and works for simple alphanumeric keys. Bracket notation ($['store']['my key']) is required when property names contain spaces, hyphens, or other special characters. Both access the same data.
How do I use recursive descent (..) in JSONPath?
The double-dot (..) searches for a key at any depth in the JSON tree. $..price finds every "price" value in the entire document regardless of nesting depth. $.store..price finds all "price" values under "store". It is equivalent to a depth-first search.
How do I filter a JSON array with JSONPath filter expressions?
Use a filter expression: $[?(@.field == value)]. The @ symbol refers to the current element. For example, $.users[?(@.age > 30)] returns all users older than 30. Supported operators: ==, !=, >, <, >=, <=.
How do I get the last element of a JSON array with JSONPath?
Use a negative index: $[-1]. Negative indices count from the end of the array. $[-1] is the last element, $[-2] is the second-to-last, and so on.
What does the wildcard [*] do in JSONPath?
The wildcard [*] selects all children of the current element. $.employees[*].name returns the name of every employee. $[*] at the root selects all top-level elements of an array.
Does JSONPath support regular expressions?
Standard JSONPath (RFC 9535) supports regex in filter expressions, but implementations vary. The jsonsql.dev evaluator supports comparison operators (==, !=, >, <, >=, <=) and existence checks. For regex matching, consider using the SQL mode with LIKE operators.
How do I select multiple array elements with array slicing?
Use slice syntax [start:end:step]. For example, $[0:3] selects the first 3 elements (indices 0, 1, 2). $[::2] selects every other element. $[1:] selects all elements except the first. Negative indices work too: $[-3:] selects the last 3 elements.
What is the difference between JSONPath and jq syntax?
JSONPath uses $ as the root and dot/bracket notation ($..store.books[0].title), while jq uses a pipe-based functional syntax (.store.books[0].title | length). JSONPath is a read-only query language defined in RFC 9535; jq is a full transformation language with functions, variables, and string interpolation.
How do I check if a field exists using JSONPath?
Use an existence filter: $[?(@.email)] returns all elements that have an email field. This checks for the presence of the key regardless of its value — even null values match. To check for non-null, combine with a comparison: $[?(@.email != null)].
Can I combine multiple filter conditions in JSONPath?
Yes. Use && for AND and || for OR inside filter expressions. For example, $[?(@.age > 25 && @.department == "Engineering")] matches elements where both conditions are true. Parentheses can group conditions for complex logic.