Open yankov opened 8 years ago
@yankov
Yup, jmespath is outstanding.
The basic idea is to transform any JSON structure into a list of hashes (aka list of objects) (aka list of dictionaries), and then perform the filter queries on that.
c == 100
[b][?c==`100`].c
a == 1
[@][?a==`1`].a
Head on over to the jmespath site and experiment with the jmespath in-browser REPL. The jmespath tool allows you to transform anything into a list, which can easily be filtered or queried however you want.
How about the following?
{
'a': {'v1': 100},
'b': {'v1': 200},
'c': {'v1': 100},
}
How can I get all the elements that match v1==100
?
@dbarrosop
Yup, jmespath is outstanding.
First off, we will want to make sure the JSON is well-formed with JSON-compatible syntax.
{
"a": {"v1": 100},
"b": {"v1": 200},
"c": {"v1": 100}
}
Then it is a simple matter of applying the approach specified previously. Transform the JSON structure into a list of objects, and then perform the filter queries on that.
Below is a screenshot of a
solution, which was entered and verified in the JMESPATH in-browser tutorial.
[a, b, c]
with the output list of objects. This can be done also.Thanks for the beautiful examples. I've been searching for how I can preserve the initial association keys (the data I need).
For instance, for the following:
{
"1CR": {
"disabled": 0,
},
"ABY": {
"disabled": 1,
},
"AC": {
"disabled": 1,
},
"ACH": {
"disabled": 0,
}
}
I want to get ["1CR", "ACH"]
, ie. all the ones with disabled == 0
.
I can easily use: * | [?disabled==\
0`]to get
[{"disabled": 0}, {"disabled": 0}]`
@dreftymac
Hi ! can you describe way to get initial association of keys ?
@Leo-need the examples that I gave above are not all optimal for JmesPath (for example the one that got a thumbs-down).
If you would like, you can paste a "BEFORE and AFTER" example ... show the JSON before, and then what you want to get after applying JmesPath.
For even better results you may want to post a question on StackOverflow.
Hi, sorry if this is not the correct place to ask, but I will try.
From the JSON below, how can I get all obj
elements that contais attr
with key == "attr 2"
?
{
"top": [
{
"obj": [
{
"obj_id": "id 1",
"attr": [
{
"key": "attr 1",
"value": "value 1"
},
{
"key": "attr 2",
"value": ""
}
]
}
]
},
{
"obj": [
{
"obj_id": "id 2",
"attr": [
{
"key": "attr 1",
"value": "value 1"
}
]
}
]
}
]
}
Maybe gets you closer?
top[?obj[?attr[?key=='attr 2']]][].obj
[
[
{
"obj_id": "id 1",
"attr": [
{
"key": "attr 1",
"value": "value 1"
},
{
"key": "attr 2",
"value": ""
}
]
}
]
]
@dwbelliston , I am trying to do something similar and I found your post useful. Thanks!
Ok so this issue is from 2016 and nobody was able to contribute a working solution to the original question yet.
@BenjaminSchaaf gave a great and concise test case in case any jmespath experts stop by in the future
I'm not one, but I did manage to solve this exact problem in my specific usecase of trying to filter such data in ansible:
- name: Find unformatted disks
set_fact:
RAW_DISKS: "{{ ansible_devices | dict2items | json_query(\"[?value.model=='Virtual Disk' && value.vendor=='Msft' && length(value.partitions) == `0`].key\") }}"
this is an ansible task that, in an Azure VM, will find all connected but not formatted disks - like when you just added a new data disk. This is not a pure jmespath solution, it could only be done with the ansible dict2items
filter, but at least I finally got this working - in case it helps anybody else who's spent hours googling.
The ansible_devices
JSON is huge, so I can only post a cut-down excerpt to better demonstrate how this is exactly like @BenjaminSchaaf example:
"ansible_devices": {
"loop0": {
"model": null,
"partitions": {},
"vendor": null
# ... lots more data ...
},
"md0": {
"model": null,
"partitions": {},
"vendor": null,
# ... lots more data ...
},
"sda": {
"model": "Virtual Disk",
"partitions": {
"sda1": {
# ... lots of data about the partition ...
},
"sda2": {
# ... lots of data about the partition ...
}
},
"vendor": "Msft",
# ... lots more data ...
},
"sdb": {
"model": "Virtual Disk",
"partitions": {},
"vendor": "Msft",
},
# ... lots more devices ...
}
I need to know the key ('sdb' in this case) so I cannot flatten these objects in the way some people have suggested.
The problem with the ansible-specific approach suggested here: https://stackoverflow.com/a/48038673 is that this will only grab the last disk or other item from the loop, I need ALL matching json objects though (disks in my case).
This isn't a universal answer like I said, but at least it works for ansible.
@jantari Thanks buddy, your solution worked like a charm 💯
There are a lot of examples on how to filter lists, but that doesn't seem to work on non-list objects. Example:
If I want to filter by
c == 100
this will not workb[?c==100]
. What should be used instead? Also how to filter bya == 1
?