问题
I have a dictionary of packages with package-name being the key and a dictionary of some details being the value:
{
"php7.1-readline": {
"latest": "7.1.9-1+ubuntu14.04.1+deb.sury.org+1",
"origins": [
"ppa.launchpad.net"
],
"version": "7.1.6-2~ubuntu14.04.1+deb.sury.org+1",
"www": "http://www.php.net/"
},
"php7.1-xml": {
"latest": "7.1.9-1+ubuntu14.04.1+deb.sury.org+1",
"origins": [
"ppa.launchpad.net"
],
"version": "7.1.6-2~ubuntu14.04.1+deb.sury.org+1",
"www": "http://www.php.net/"
},
"plymouth": {
"version": "0.8.8-0ubuntu17.1"
},
....
}
I'd like to reduce the above to a dictionary with only the packages, that have the latest
-attribute in their values.
It would seem like json_query
is the filter to use, but I can't figure out the syntax. The examples out there all seem to operate on lists of dictionaries, not dictionaries of same...
For example, if I "pipe" the above dictionary into json_query('*.latest')
, I get the list of the actual latest versions:
[
"7.1.9-1+ubuntu14.04.1+deb.sury.org+1",
"7.1.9-1+ubuntu14.04.1+deb.sury.org+1",
"7.1.6-2~ubuntu14.04.1+deb.sury.org+1"
]
How can I get the entire dictionary-elements instead?
Any hope?
回答1:
With dict2items
filter added in December 2017, it is possible using native functionality:
- debug:
msg: "{{ dict(pkg | dict2items | json_query('[?value.latest].[key, value.latest]')) }}"
The result:
"msg": {
"php7.1-readline": "7.1.9-1+ubuntu14.04.1+deb.sury.org+1",
"php7.1-xml": "7.1.9-1+ubuntu14.04.1+deb.sury.org+1"
}
回答2:
You can't perform this translation (I think) exclusively with Jinja filters, but you can get there by applying a little Ansible logic as well. The following playbook uses a with_dict
loop to loop over the items in your dictionary, and build a new dictionary from matching ones:
- hosts: localhost
vars:
packages: {
"php7.1-readline": {
"latest": "7.1.9-1+ubuntu14.04.1+deb.sury.org+1",
"origins": [
"ppa.launchpad.net"
],
"version": "7.1.6-2~ubuntu14.04.1+deb.sury.org+1",
"www": "http://www.php.net/"
},
"php7.1-xml": {
"latest": "7.1.9-1+ubuntu14.04.1+deb.sury.org+1",
"origins": [
"ppa.launchpad.net"
],
"version": "7.1.6-2~ubuntu14.04.1+deb.sury.org+1",
"www": "http://www.php.net/"
},
"plymouth": {
"version": "0.8.8-0ubuntu17.1"
}
}
tasks:
- set_fact:
new_packages: >
{{ new_packages|default({})|
combine({item.key: item.value}) }}
with_dict: "{{ packages }}"
when: "{{ item.value.latest is defined }}"
- debug:
var: new_packages
回答3:
You are correct to link this question to https://stackoverflow.com/a/41584889/2795592.
There are no options to manipulate keys and values simultaneously with json_query out of the box (as of Ansible 2.4.0).
Here's patched json_query.py that supports jq-like to_entries
/from_entries
functions.
You can put it into ./filter_plugins
near your playbook and make this query:
- debug:
msg: "{{ pkg | json_query('to_entries(@) | [?value.latest].{key:key, value:value.latest} | from_entries(@)')}}"
to get this result:
"msg": {
"php7.1-readline": "7.1.9-1+ubuntu14.04.1+deb.sury.org+1",
"php7.1-xml": "7.1.9-1+ubuntu14.04.1+deb.sury.org+1"
}
I'll make PR to ansible as soon as I have some spare time.
来源:https://stackoverflow.com/questions/46306363/how-to-filter-dictionaries-in-jinja