contains
:list[?contains(grades, 'a')].student
list[?!(contains(grades, 'a'))].student
Hi there,
I have a question regarding literal wrapping.
According to the JMESPATH specification, the wrapping character is supposed to be backtick:
literal = "`" json-value "`"
However, I see lots of examples in this chat using simple quotes and backticks interchangeably.
And indeed the JMESPath implementation used in the online evaluator supports simple quotes as well.
But then, other implementations don't, eg the Java one.
IMHO, this is a bug and all implementations should strictly abide to the specification (that's the whole point of JMESPath compared to JsonPath).
(original discussing here: https://community.gatling.io/t/jmespath-is-not-finding-a-json-object/6995)
Thoughts?
@hell-racer There's one in the Gatling forum post I provided.
{
"status":"GOOD",
"fruits":[
{
"name":"Apple",
"details": {
"size":500
}
},
{
"name":"Cherry",
"details": {
"size":100
}
}]
}
On https://jmespath.org/, both following expressions work.
With quotes:
fruits[?details.size >= '500']
With backticks:
fruits[?details.size >= `500`]
Only the latter would work with https://github.com/burtcorp/jmespath-java
Yeah... I meant some examples of single quotes in such context in JmesPath documentation.
I don't think there's one. The documentation matches with the specification.
Anyway, in my opinion, it should return empty array when filtering by '500' while the values are numbers in source data.
Agree. I would have liked to open an issue against the JMESPath implementation used for the online evaluator on https://jmespath.org/ but I don't know which one it is. Do you know?
@slandelle you are right, you are not crazy š.
For the record, JMESPath used to support strings using this syntax: `this was a string`
.
However, JEP-12 made this syntax obsolete.
Now, the grammar is much clearer. You can only have:
quoted-string
: simple JSON strings easy to input using simple quotes. e.g 'hello world!'
.raw-string
literals : JSON values typed verbatim (except, backtick must be escaped). e.g `"{}`"
would be an empty JSON object. Please, note that a JSON string has surrounding double quotes, and thus mus be input like so `"this is a string"`
.Your question is raised in the context of numeric literals. JMESPath does not support JSON numbers in its grammar. So those must be input using raw-string
literals. Thus:
fruits[? details.size >= `500` ]
filters all fruits whose size is greater than number 500
. fruits[? details.size >= '500' ]
filters all fruits whose size is greater than string "500"
. Probably not what you want.Comparisons between numbers and strings is currently undefined in the grammar as ordering operators are only valid between two numbers. However, popular implementations do make some attempt to cast the string to a number before performing the comparison, so it mostly works even though it is not standards-compliant.
Comparisons between numbers and strings is currently undefined in the grammar as ordering operators are only valid between two numbers. However, popular implementations do make some attempt to cast the string to a number before performing the comparison, so it mostly works even though it is not standards-compliant.
If you guys are considering JMESPath 2.0, should this String comparison be made a standard?
{
"Code": 1000,
"GlobalServers": [
{
"Name": "bar",
"Country": "IS",
"Status": 1,
"Servers": [
{
"Name": "foo",
"Status": 1
}
]
}
]
}
But I am struggling to filter it.
GlobalServers[?Status==1
].... works
but then if I try
GlobalServers[?Status==1
].Servers[?Status==1
] ...I get no ouput
Hi! At this point
GlobalServers[?Status==`1`].Servers
... you have an array of arrays:
[
[
{
"Name": "foo",
"Status": 1
}
]
]
So you have to flatten it and stop the projection before filtering:
GlobalServers[?Status==`1`].Servers[]|[?Status==`1`]
Output:
[
{
"Name": "foo",
"Status": 1
}
]
GlobalServers[?Status==`1`].merge(@, { Servers: Servers[?Status==`1`] })
merge(@)
worked great. Thank you again !
@hell-racer: There's one more thing, I was hoping to find the answer myself but I can't find the right way to do it. Building on your "GlobalServers[?Status==1
].merge(@, { Servers: Servers[?Status==1
] })".....
The GlobalServers parent node has a "score" value for each entry, I would like to only return the node for the highest score (that also matches the filter).
So far the nearest I have managed to get is this:
"max_by(GlobalServers[],&Score).merge(@, { Servers: Servers[?Status==1
] })"
But no matter how I try to integrate the original GlobalServers filter, I can't manage do to it. I've tried putting max_by() before the filter, after the filter, inside the filter ... jmespath complains each time.
It returns ERR_CONNECTION_RESET :(.
Ok, on the site https://jmespath.org/ given input:
{
"Code": 1000,
"GlobalServers": [
{
"Name": "bar1",
"Country": "IS",
"Score": 1,
"Servers": [
{
"Name": "foo1",
"Status": 1
},
{
"Name": "foo2",
"Status": 2
}
]
},
{
"Name": "bar2",
"Country": "US",
"Score": 2,
"Servers": [
{
"Name": "foo",
"Status": 1
},
{
"Name": "foo2",
"Status": 2
}
]
}
]
}
Your query:
max_by(GlobalServers, &Score).merge(@, { Servers: Servers[?Status==`1`] })
Returns:
{
"Name": "bar2",
"Country": "US",
"Score": 2,
"Servers": [
{
"Name": "foo",
"Status": 1
}
]
}
[]
in the GlobalServers[]
.