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[]
.
1
] })" works. But that's not my problem. I still need to integrate the original "GlobalServers[?Status==1
]" parent filter and I can't find a way to do that in conjunction with max_by()
1
].max_by(GlobalServers, &Score).) or something like that
GlobalServers[?Status == `1`]|max_by(@, &Score).merge(@, { Servers: Servers[?Status==`1`] })
The problems with
GlobalServers[?Status==1].max_by(GlobalServers, &Score) ...
... are these:
.
after that, it will evaluate everything after the .
in context of single element of the filtered array, so max_by
will treat a single item as array and try to find max in it. So you have to stop the projection, to allow the next function to operate on the entire filtered array..
to |
you are now in context of the filtered array of GlobalServers
, so you have to use @
to refer to it instead of GlobalServers
.In some respects it would be nice if the docs had a couple of "real-world" examples with slightly trickier syntax rather than just the simple one-liners based on simple tasks.
Thanks for the feedback. We will try and update the spec accordingly.
I think I have a mental model that works for explaining what are projections and how they work.
Imagine a JMESPath expression as a pipeline, like a series of more focused expressions that process input and produce output.
While the input and output of the whole JMESPath expression is always a JSON token, what flows through the pipeline can be thought of as either of two things:
I define a "projection" as being a list of JSON tokens (very similar to a JSON array).
But the difference is, while a JSON array is passed as a single value to the downstream expression in the pipeline, a "projection" sees its elements branch off individually to the downstream expression.
The only way to fold a projection back to a regular JSON array is to either use a |
or to exit the pipeline. That is, if the result of the evaluation ends with a "projection", the JMESPath evaluation engine folds the result to JSON array.
Consider the following input JSON document:
[
{ "name": "jack" },
{ "name": "john" }
]
Consider the following very similar expressions:
search( [*].name.length(@), …) -> [4, 4]
search( [*].name|length(@), …) -> 2
[*]
, the output is a projection, i.e a list containing two JSON objects that must be projected to the downstream expression name
.name
happens twice, once for each element in the projection, and returns a new projection, i.e a list of two JSON strings.Using .
in a sub-expression
.
in sub-expression
, the two JSON strings in the projection are projected onto the length(@)
expression.length()
function which outputs a JSON number.Using |
in a pipe-expression
|
in a pipe-expression
, however, the projection is folded back to a regular JSON array immediately.name
properties in the original JSON document.length()
function, which returns a JSON number.true
]."ifname"
The source data is weird as the data
property is an array of JSON objects, each of which has a different schema.
So your expression makes it look like you want to find all JSON objects in data
where there exists a property whose value is ORD001
– thereby returning the single object { "description": "ORD001 | Singapore" }
from the collection.
From there, you seem to want to return the value of the ifname
property for that object. As the single matching object does not have an ifname
property, the whole expression would return null
.
Can you clarify your exact requirements ?
merge(data).(contains(description, 'ORD001') && ifname || null)
but merge is variadic and cant accept a list of objects. I also don't think that a spread operator is what is needed, we just need to replace all variadic functions.