Hey people, i hope this is the correct place to ask, i'm trying my hand with jmespath, and i've ran into some null value issues, i've tried looking around on stackoverflow and the documentation, but i havnt been able to find any solution to my issue:
I've got the following:
{
"items": [{
"val1": "some",
"val2": null
}, {
"val1": "other",
"val2": "value"
}]
}
To which i apply the transformation:items[*].{newValue:join(' - ',[val1, val2])}
However, it doesnt work, as items[0].val2 has the value 'null', is there some way to look through properties and replace null values with a default value, emptystring in this case.
Name Is Secret Value
bearer_token False
org_id True
org_id1 False dhsakjfhakjshfkjdahf
owner_id True
owner_id1 False mdfjsadhfkjsdahfkjsdhf
password True
password1 True
projectid False
username False testtest
username1 False test
Hi! I need some help with a json query. My data (simplified and to yaml) is
network:
ipfabric:
lab:
links:
- nodes:
"h01":
interface: "swp1"
ip: 192.168.253.180
"h02":
interface: "eth0"
ip: 192.168.253.250
networks:
ip4:
cidr: 192.168.253.0/24
bfd: yes
bgp: yes
- nodes:
"h01":
interface: "swp2"
ip: 192.168.23.180
"h04":
interface: "eth2"
ip: 192.168.23.250
networks:
ip4:
cidr: 192.168.253.0/24
bgp: yes
I'm querying for all interfaces on "h01" with ipfabric.*.links[*].nodes.h01.interface[]
which works fine ... But:
ipfabric.*.links[? bfd == `yes`].nodes.h01.interface[]
Based on your sample data structure above, I "think" this is what you were hoping for:
ipfabric.lab.links[?bfd == `yes`].nodes.h01.interface
Since I do most of my testing in Ansible, one note I will add is that yes
translates to True
, so I had to wrap the yes
in single quotes to stop it from processing as a boolean value. If you are using the same, you can change it to this to search for the Boolean True
instead of the string yes
:
ipfabric.lab.links[?bfd == `true`].nodes.h01.interface
Re-reading what you wrote, I think I am gathering the picture. lab
also has other similar environments that need to be searched for thus needs to be wildcard'ed if I am understanding right...trying this:
ipfabric.*[].links[?bfd == `true`].nodes.h01.interface | []
The thing about using the dictionary wildcard ipfabric.*
converts the what you would expect to be dict results, actually converts it to a list. You can tell by doing this:
ipfabric.*
You will notice the top results is a list now, instead of a dictionary. To get past this conversion I simply flatten the list result from the asterisk and keep going. At the end you will notice that there is a list within a list, because of the flattening...so I pipe to another flatten and thus I think is the end goal you were hoping?
true
) and I also get an empty list. So somehow it doesn't return anything after the filtering. I cut down from the end to see if I miss something.
true
- but the same does not work for yes
It seems like you found your issue but I had already typed this out, and it is a helpful gem for new users and testing so I sent it anyways:
For JMESPath testing, I always start at the beginning and make my way down the rabbit hole, so to speak.
Start by commenting out the | json_query(jmespath_query)
Then if that works, uncomment it and start cutting down the jmespath_query filter one step at a time...like so:
ipfabric.
ipfabric.*
ipfabric.*[]
ipfabric.*[].links
ipfabric.*[].links[?bfd == `true`]
ipfabric.*[].links[?bfd == `true`].nodes
ipfabric.*[].links[?bfd == `true`].nodes.h01
ipfabric.*[].links[?bfd == `true`].nodes.h01.interface
ipfabric.*[].links[?bfd == `true`].nodes.h01.interface | []
If you don't see results from the first comment, then you know the variable network
is not the right one you should use in yours...look at where your data is coming from and change accordingly. If its in the jmespath filter, you will see it break (empty results) eventually and know where your query needs to be updated.
Your original query was accurate in my opinion...I think the only problem you had was due to ipfabric.*.links
as that would never yield results because the asterisk converts the dict to a list of matching dicts... so we had to deal with that by adding the flattener right after the asterisk:
ipfabric.*[].links
The rest was on par I believe (minus of course Ansible's fun yes/no to boolean good times). :)
ipfabric.* | [].links[?bfd].nodes.h01.interface | []
@jwalzer -
Be sure to use this little nugget with JMESPath and Ansible if you ever attempt to use functions in JMESPath with Ansible such as map, ends_with, et...:
- name: JMESPath Testing
vars:
jmespath_query: >-
ipfabric.* | [].links[*].nodes.h01.interface | [] | [?ends_with(@,'1')]
debug:
var: network | json_query(jmespath_query)
By all accounts this should work but you find that you get a "type" error:In function ends_with(), invalid type for value: swp1, expected one of: ['string'], received: \"unknown
This is due to Ansible's data types not matching the JSON spec is what I believe is the root cause. To fix it simply add the to_json and from_json syntax before the json_query and profit.
- name: JMESPath Testing
vars:
jmespath_query: >-
ipfabric.* | [].links[*].nodes.h01.interface | [] | [?ends_with(@,'1')]
debug:
var: network | to_json | from_json | json_query(jmespath_query)
[{
"backup": "b3",
"time_ended": "2020-09-10T14:55:39.840000+00:00"
}, {
"backup": "b2",
"time_ended": "2020-08-25T15:40:48.740000+00:00"
}, {
"backup": "b1",
"time_ended": "2020-07-10T15:40:48.740000+00:00"
}]
@alonsocamaro - THe homepage for JMESPath can be used as an online evaluator if desired. Its a real-time test and you can manipulate the search and json structure that will be searched.
I have not ran into an issue where it has "failed" for me thus far unless there is an error in my syntax which is most likely the cause of your not updating. That is one area where it lacks is it doesn't let you know when the syntax has an error so its likely assumed to be a web-based error. If you have a specific scenario/filter feel free to type it here and if I am paying attention will attempt to help.
I asked this on stackoverflow as well, but thought I'd ask it here to try and get some traction.
AWS's list-secrets
has an odd way of listing version strings as keys:
{
"SecretList": [
{
"Name": "sandbox_config",
"Description": "sandbox config file",
"SecretVersionsToStages": {
"2895f1a4-bcae-46b2-9a45-4f06f490d8ed": [
"AWSCURRENT"
],
"336a5030-cd81-4626-a100-1aa68b70b5b1": [
"AWSPREVIOUS"
]
}
}
]
}
I'm trying to figure out a query that will let me pull out the versionkey where AWSCURRENT
is in the value array.
This seems like it's close:
SecretList[].{Version:SecretVersionsToStages.*[?@==`AWSCURRENT`]|[]|[0] }
But I'm clearly missing something, since that just spits back AWSCURRENT
to me.
If you could... would you want to be able to do something like this:
expect(
search([6.1, 4.2, 6.3], "_groupBy(@, as_lambda('Math.floor'))")
).toStrictEqual({
'4': [4.2],
'6': [6.1, 6.3],
});
or perhaps
expect(
search([1, 2], "_flatMap(@, as_lambda('x => [x, x]'))")
).toStrictEqual([1, 1, 2, 2]);
Thoughts?