Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    hansenjohansen
    @hansenjohansen:matrix.org
    [m]
    Regarding your answer, yes "max_by(GlobalServers, &Score).merge(@, { Servers: Servers[?Status==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()
    hell-racer
    @hell-racer
    So filter by status then select max by score?
    That makes sense )
    hansenjohansen
    @hansenjohansen:matrix.org
    [m]
    Yeah, I already tried that construct (if you're thinking "GlobalServers[?Status==1].max_by(GlobalServers, &Score).) or something like that
    In terms of concept yes ... not much point picking a high-scoring dead server. ;-)
    hell-racer
    @hell-racer
    max_by(GlobalServers[?Status == `1`], &Score).merge(@, { Servers: Servers[?Status==`1`] })
    hansenjohansen
    @hansenjohansen:matrix.org
    [m]
    Now that's one of the hundreds of combinations I didn't try !
    ;-)
    hell-racer
    @hell-racer
    :)
    Another way would be:
    GlobalServers[?Status == `1`]|max_by(@, &Score).merge(@, { Servers: Servers[?Status==`1`] })
    hansenjohansen
    @hansenjohansen:matrix.org
    [m]
    Yeah, that seems to run great with my static test JSON.
    Regarding your second suggestion of the pipe, I'm sure I tried that, but maybe my syntax was slightly off.
    hell-racer
    @hell-racer

    The problems with

    GlobalServers[?Status==1].max_by(GlobalServers, &Score) ...

    ... are these:

    1. After initial filtering you're in a projection, e.g. if you add . 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.
    2. Now if you change . to | you are now in context of the filtered array of GlobalServers, so you have to use @ to refer to it instead of GlobalServers.
    hansenjohansen
    @hansenjohansen:matrix.org
    [m]
    Thanks for the nice clear explanation. Much appreciated @hell-racer jmespath is a wonderful tool, but also devilishly tricky to learn !
    hell-racer
    @hell-racer
    But once you learn it you feel the power like a wizard :)
    hansenjohansen
    @hansenjohansen:matrix.org
    [m]
    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.
    At some point I even considered running jmespath twice for my application (once to save "max" to a variable and the second to use it in the filter). But I thought surely there must be a way to do it as one, hence I came back to ask the wizards here !
    hell-racer
    @hell-racer
    I think projections is most difficult topic and definitely needs more examples.
    Maxime Labelle
    @springcomp

    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:

    • A JSON token
    • A "projection"

    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.

    So if you use a hash-wildcard-expression on an input JSON array, the result will be a projection, that is, a list of JSON elements, each of which will go through the downstream expression.
    Maxime Labelle
    @springcomp

    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
    1. The input of both entire expressions are a JSON array.
    2. After evaluating the first expression in the pipeline, [*], the output is a projection, i.e a list containing two JSON objects that must be projected to the downstream expression name.
    3. Evaluating the identifier name happens twice, once for each element in the projection, and returns a new projection, i.e a list of two JSON strings.
    4. Now, that’s where the two expressions differ.

    Using . in a sub-expression

    • When using a . in sub-expression, the two JSON strings in the projection are projected onto the length(@) expression.
    • Each JSON string is sent as the first argument to the length() function which outputs a JSON number.
    • Both JSON numbers are aggregated, the result being yet another projection, ie a list of two JSON numbers.
    • Since this is the end of the entire expression, the JMESPath evaluation engine folds the projection to a regular JSON array.

    Using |in a pipe-expression

    • When using a | in a pipe-expression, however, the projection is folded back to a regular JSON array immediately.
    • The JSON array contains two JSON strings, each of which is the value for the name properties in the original JSON document.
    • This array is passed as the first argument to the length() function, which returns a JSON number.
    • Since this is the end of the entire expression, that is what the JMESPath evaluation engine returns.
    hansenjohansen
    @hansenjohansen:matrix.org
    [m]
    thanks @springcomp I've copied pasted that and will re-read at leisure and experiment a bit to try to grasp the topic a bit better. Appreciate the input.
    hell-racer
    @hell-racer
    @springcomp that's awesome :). I'll keep this in my notes.
    Maxime Labelle
    @springcomp
    @/all, JMESPath Community’s next milestone is taking shape. Please, feel free to provide feedback.
    Maxime Labelle
    @springcomp
    I think @innovate-invent did a really good job documenting that in our JMESPath Community version.
    Nolan Woods
    @innovate-invent
    I can't take credit, it was taken from the original site
    Maxime Labelle
    @springcomp
    Well, @innovate-invent, the official spec does not document slice-expression and filter-expression as being projections. At least, not explicitly and as clearly as you have done.
    Nolan Woods
    @innovate-invent
    I am not entirely sure where that came from
    I didn't write it... unless I am seriously gapping out
    codesupremojr
    @codesupremojr
    'Hello, any idea on how to filter the description that contains the word 'ORD001' and the output will be the 'ifname' value? Please see below jsondata, I tried to follow the example showin in jmespath website but it's still not working for me. Thank you so much in advanced! :)
    {
    "data": [
    {"ifname": "ge2/0"},
    {"router": "router001"},
    {"description": "ORD001 | Singapore"},
    {"status": "Up"}
    ]
    }
    I tried this filter, data[?contains(@, 'ORD001') == true]."ifname"
    but not working for me
    anything I missed? Thanks a lot
    Maxime Labelle
    @springcomp

    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 ?

    JosephJohnKarl
    @JJKW1984
    Hello
    Nolan Woods
    @innovate-invent
    I think @codesupremojr highlights the issue with having variadic functions like merge(). This could easily be done with 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.
    This is also not syntactically possible given that subexpression doesn't allow parenthesis
    Nolan Woods
    @innovate-invent
    (assuming 'data' is within some sort of projection)
    snowplayfire
    @snowplayfire
    how can i get value from a map with certain key?
    Nolan Woods
    @innovate-invent
    can you provide an example?
    hell-racer
    @hell-racer
    No example provided, timeout expired, issue automatically closed. (c)
    Maxime Labelle
    @springcomp
    🤣
    By any chance, @hell-racer , have you had a try to our proposal for arithmetic-expressions ?
    hell-racer
    @hell-racer
    I didn't even know there is a sandbox for preview features ))
    hell-racer
    @hell-racer
    Still looks like the necessity to create an object to be able to use arithmetic operations with values from different levels of source data makes them hard to use... I get that the other options are hard to implement, and expressions themselves may be hard to reason about, but...
    Maxime Labelle
    @springcomp
    No, no, your original expression works. You can try it out : a.b + c.d. Nice and easy !
    It’s the same as a.b || c.d really.
    image.png
    hell-racer
    @hell-racer
    OMG!