Examples: click one to load its JSON and query
Engine: @jmespath-community/jmespath 1.3.0, running in a Web Worker. Your JSON and queries never leave your browser; nothing is stored.
Run JMESPath queries against JSON in your browser — your JSON and queries never leave your browser, and nothing is uploaded.
Examples: click one to load its JSON and query
Engine: @jmespath-community/jmespath 1.3.0, running in a Web Worker. Your JSON and queries never leave your browser; nothing is stored.
JMESPath is a query language for JSON. An expression such as people[?age > `30`].name picks out matching parts of a document and returns them as JSON. It has a written specification and a shared compliance test suite, and the AWS CLI and Azure CLI both use it for their --query option.
This tester runs @jmespath-community/jmespath 1.3.0, an open-source JavaScript library under the MPL-2.0 licence (source repository),
inside a Web Worker. Run through this page's own code, the official compliance suite (16 test files, 892 cases) gives
891 passes. The one difference: a doubled backslash in a raw string becomes one backslash, where the
older test expects two. The page follows the JMESPath specification, but the AWS CLI, the Azure CLI and other tools implement it themselves,
so edge cases can differ.
The library also adds features that are not in the specification, and queries that use them fail in tools that implement only the
specification. The extra functions are find_first, find_last, from_items, group_by, items, lower, pad_left, pad_right, replace, split, trim, trim_left, trim_right, upper, zip. The extra syntax is arithmetic,
let variables, a $ root reference, and slicing of strings (people[0].name[0:3] gives "Ada"). The page notes it under a query that uses any of them.
Use a filter expression in square brackets: people[?age > `30`].name returns the names of everyone over 30. The ? starts a condition, backticks hold JSON literals such as numbers, and single quotes hold plain strings. Filters work on arrays only, and an item that fails the condition is simply left out.
A filter can combine conditions with && and || and call functions, as in people[?contains(tags, 'code')].name, which returns ["Ada Lovelace","Margaret Hamilton"].
Then continue: people[?age > `30`] | length(@) counts the matches and gives 3. To inspect the data first, format the result with the JSON Formatter; the JSON Schema Validator checks its shape.
A projection such as people[*].name applies the part after it to every item in an array. A trailing [] flattens one level of nesting, so Reservations[].Instances[].InstanceId turns nested lists into one flat list. Projections skip null results, which is why missing values never appear in the output.
Without the flatten, Reservations[*].Instances[*].InstanceId keeps one inner list per reservation and gives [["i-0a1","i-0b2"],["i-0c3"]]. With it, Reservations[].Instances[].InstanceId gives
["i-0a1","i-0b2","i-0c3"]. A multiselect list such as people[*].[name, age] builds one array per item, and a multiselect hash such as people[*].{who: name, years: age} builds one
labelled object per item.
Both select parts of JSON, but they are different languages. JSONPath paths start with $, can search at any depth with .., and always return a list of matches. JMESPath returns a bare value or a list, has built-in functions such as sort_by, and needs an explicit path instead of a recursive search.
The table runs the same selections in both languages. The JMESPath results come from this page's worker; the JSONPath results come from
jsonpath-plus 11.1.1, the library behind the JSONPath Tester, with the same options
that page uses. Neither is better: they suit different jobs. For background on JSONPath itself, see the guide to JSONPath.
| Selection | JMESPath and its result | JSONPath and its result |
|---|---|---|
| The same selection | people[?age > `30`].name["Ada Lovelace","Grace Hopper","Margaret Hamilton"] | $.people[?(@.age > 30)].name["Ada Lovelace","Grace Hopper","Margaret Hamilton"] |
| One value | people[0].name"Ada Lovelace" | $.people[0].name["Ada Lovelace"] |
| Searching at any depth | people[*].address.city["London","New York","Boston"] | $..city["London","New York","Boston","Paris"] |
The last row is a real difference. JSONPath's $..city finds every city key at any depth, including company.hq.city.
JMESPath has no recursive search, so the query has to name each place, for example [people[*].address.city, company.hq.city], which gives [["London","New York","Boston"],"Paris"]. Another: JSONPath always returns a list, JMESPath a bare value.
A JMESPath query returns null when a key is missing, when the value really is null, or when a step does not apply, such as a filter on something that is not an array. A valid query that matches nothing is not an error, so null alone does not tell you which of these happened.
people[2].address is a JSON null and people[2].nothing is a missing key, and both give null. Even type() returns "null" for both."first name" gives "Ada", while first name is a syntax error. A dash is a trap: unquoted a-b gives 3 here, because this library reads it as subtraction, whereas a tool that follows the specification only would report a syntax error. Write "a-b".name == 'London' and name == `"London"` both give true. But age == '30' gives false, because '30' is a string and the age is a number, while age == `30` gives true. A bare word such as name == London is read as a key and gives false.`[1, 2]` gives [1,2], but `foo` is rejected: Syntax error: unexpected end of JSON input or invalid format for a JSON literal: `.people[*].address returns three of four people, and people[*].address.city gives ["London","New York","Boston"], skipping the person whose address is null. Projecting a string, as in people[0].name[*], gives null.12345678901234567890 comes back as 12345678901234567000 and 9007199254740993 as 9007199254740992. This page warns before running when the input has integers beyond 253; it has no custom number parser.sort_by(m, &v) fails with Invalid type: expected (number), received string, while numbers alone work: sort_by(m, &v)[*].v gives [1,2].abs(people) fails with Invalid type: abs() expected argument 1 to be type (number) but received type array instead., and length(people, people) fails with Invalid arity: length() takes 1 argument but received 2. Convert text first with to_number(people[0].score), which gives 91.5.people[?name > 'B'].name gives [], because comparing strings with > never matches, while people[?age >= `36`].name gives ["Ada Lovelace","Grace Hopper","Margaret Hamilton"].__proto__ gives null when the data has no such key. The library alone would return the empty object prototype there, so the page copies the data into prototype-less objects when a query mentions it. A key named __proto__ in a multiselect hash is dropped by the library, and the page says so under the query.lower(), arithmetic, let, $ or string slicing, gets a note listing them, because the AWS CLI and other implementations may reject it.The examples below were each run through this page's own code against small sample documents. Click any of them in the examples panel above to load its document and query. The output shown is the exact text this tool produced, not typed by hand, and a script re-checks it against the library.
Sample document "people"
{
"people": [
{
"name": "Ada Lovelace",
"age": 36,
"tags": [
"math",
"code"
],
"address": {
"city": "London"
},
"score": "91.5"
},
{
"name": "Grace Hopper",
"age": 45,
"tags": [
"compilers",
"navy"
],
"address": {
"city": "New York"
},
"score": "88"
},
{
"name": "Linus Torvalds",
"age": 28,
"tags": [],
"address": null,
"score": "79.25"
},
{
"name": "Margaret Hamilton",
"age": 52,
"tags": [
"apollo",
"code"
],
"address": {
"city": "Boston"
},
"score": "95"
}
]
}
| # | Query | Output |
|---|---|---|
| 1 | people[0].name | "Ada Lovelace" |
| 2 | people[*].name | ["Ada Lovelace","Grace Hopper","Linus Torvalds","Margaret Hamilton"] |
| 3 | people[?age > `30`].name | ["Ada Lovelace","Grace Hopper","Margaret Hamilton"] |
| 4 | people[?address.city == 'London'].name | ["Ada Lovelace"] |
| 5 | people[1:3].name | ["Grace Hopper","Linus Torvalds"] |
| 6 | Reservations[].Instances[].InstanceId | ["i-0a1","i-0b2","i-0c3"] |
| 7 | Reservations[].Instances[?State.Name == 'running'].InstanceId[] | ["i-0a1","i-0c3"] |
| 8 | people[?age > `30`] | length(@) | 3 |
| 9 | people[*].[name, age] | [["Ada Lovelace",36],["Grace Hopper",45],["Linus Torvalds",28],["Margaret Hamilton",52]] |
| 10 | people[*].{who: name, years: age} | [{"who":"Ada Lovelace","years":36},{"who":"Grace Hopper","years":45},{"who":"Linus Torvalds","years":28},{"who":"Margaret Hamilton","years":52}] |
| 11 | sort_by(people, &age)[*].name | ["Linus Torvalds","Ada Lovelace","Grace Hopper","Margaret Hamilton"] |
| 12 | max_by(people, &age).name | "Margaret Hamilton" |
| 13 | join(', ', people[*].name) | "Ada Lovelace, Grace Hopper, Linus Torvalds, Margaret Hamilton" |
| 14 | sum(map(&to_number(score), people)) | 353.75 |
| 15 | people[?contains(tags, 'code')].name | ["Ada Lovelace","Margaret Hamilton"] |
| 16 | keys(people[0]) | ["name","age","tags","address","score"] |
| 17 | people[*].address.city | ["London","New York","Boston"] |
| 18 | people[*].not_null(address.city, 'unknown') | ["London","New York","unknown","Boston"] |
| 19 | length(orders[?customer == 'ada']) | 2 |
The specification defines 26 built-in functions and a small set of operators: sub-expressions, indexes, slices, wildcards, flatten, filters, pipes, multiselect lists and hashes, comparisons and boolean logic. This page runs a library that adds 15 more functions and some syntax. The tables mark every addition as an extension.
| Syntax | Meaning |
|---|---|
foo.bar | Sub-expression: the key bar inside foo |
foo[0] foo[-1] | Index from the start or the end of an array |
foo[*] foo.* | Wildcard projection over an array, or over the values of an object |
foo[1:3] foo[::-1] | Slice with start, stop and step |
foo[] | Flatten one level of nesting |
foo[?bar == `1`] | Filter an array by a condition |
a | b | Pipe: run b on the whole result of a |
[a, b] | Multiselect list: a new array |
{x: a, y: b} | Multiselect hash: a new object |
&& || ! | Boolean and, or and not |
== != < <= > >= | Comparisons; ordering works on numbers only |
@ | The current node |
'text' | Raw string literal |
`json` | JSON literal, such as `30` or `[1, 2]` |
"quoted name" | Quoted identifier, for keys with spaces, dashes or a leading digit |
&expr | Expression reference, passed to functions such as sort_by |
`7` // `2` `7` % `4` `3` * `4` | Arithmetic operators + - * / // %, and unary - and + extension |
let $x = a in expr | Variables with let expressions extension |
$ | Reference to the root of the document extension |
name[0:3] | Slicing a string, which the specification limits to arrays extension |
| Function | What it does |
|---|---|
abs() | Absolute value |
avg() | Average of an array of numbers |
ceil() | Round up |
contains() | Is a value in an array, or text in a string |
ends_with() | Does a string end with a suffix |
floor() | Round down |
join() | Join an array of strings with a separator |
keys() | Keys of an object |
length() | Length of a string, array or object |
map() | Apply an expression to every item |
max() | Largest number or string |
max_by() | Item with the largest key |
merge() | Merge objects |
min() | Smallest number or string |
min_by() | Item with the smallest key |
not_null() | First argument that is not null |
reverse() | Reverse an array or string |
sort() | Sort numbers or strings |
sort_by() | Sort items by an expression |
starts_with() | Does a string start with a prefix |
sum() | Sum of an array of numbers |
to_array() | Wrap in an array |
to_number() | Convert text to a number |
to_string() | Convert to a JSON string |
type() | Type name of a value |
values() | Values of an object |
| Function | What it does |
|---|---|
find_first() | Index of the first match in a string extension |
find_last() | Index of the last match in a string extension |
from_items() | Build an object from key and value pairs extension |
group_by() | Group items by an expression extension |
items() | Key and value pairs of an object extension |
lower() | Lower-case a string extension |
pad_left() | Pad a string on the left extension |
pad_right() | Pad a string on the right extension |
replace() | Replace text in a string extension |
split() | Split a string into an array extension |
trim() | Trim whitespace from both ends extension |
trim_left() | Trim whitespace at the start extension |
trim_right() | Trim whitespace at the end extension |
upper() | Upper-case a string extension |
zip() | Pair up items of arrays extension |
No. The query runs in a Web Worker on your device, so your JSON and queries never leave your browser. Nothing you paste or upload is sent to a server, and nothing is stored. Still, do not paste secrets into any website, because pages can load third-party scripts such as the Google tag.
Queries run in the worker under a time limit with a Cancel button, and results above about 20 MB are not built. New to JSON? Read the introduction to JSON.
It runs @jmespath-community/jmespath 1.3.0 in a Web Worker in your browser. In this page's own test run it passes 891 of the 892 cases in the official JMESPath compliance suite, and it adds extra functions and syntax beyond the specification, which the page marks as extensions.
Usually, for queries written to the specification, but this page does not claim an exact match. Each command line tool has its own implementation, so edge cases can differ, and the extensions this library adds will not work in tools that implement only the specification.
The browser reads JSON numbers as 64-bit floating point, so integers beyond 2^53 can lose digits before any query runs. The page warns when it sees such numbers. If you need every digit, keep long identifiers in strings.
Uploads can be up to 50 MB, queries up to 10,000 characters, and nesting up to 5,000 levels. Above about 1 MB live mode pauses and you press Run query, and results above about 20 MB are not built. Runs have a time limit and can be cancelled.
No. Your JSON and queries never leave your browser. The tester runs in a Web Worker on your device and nothing is stored. Still, do not paste secrets into any website.
Built and maintained by Deepak Kumar. Your JSON and queries never leave your browser, and nothing you paste is uploaded.