You can use only Jinja2 tests in selectattr:
http://jinja.pocoo.org/docs/2.9/templates/#builtin-tests
http://docs.ansible.com/ansible/latest/playbooks_tests.html
For your example:
- debug:
msg: "{{ item.name }}"
with_items: "{{ network.addresses.private_man | selectattr('addr','issuperset',['1.2.3.4']) | list }}"
Answer from Konstantin Suvorov on Stack OverflowYou can use only Jinja2 tests in selectattr:
http://jinja.pocoo.org/docs/2.9/templates/#builtin-tests
http://docs.ansible.com/ansible/latest/playbooks_tests.html
For your example:
- debug:
msg: "{{ item.name }}"
with_items: "{{ network.addresses.private_man | selectattr('addr','issuperset',['1.2.3.4']) | list }}"
Will this work?
- debug:
msg: "{{ item.name }}"
with_items: "{{network.addresses.private_man}}"
when: '"1.2.3.4" in item.addr'
Edit: I actually didn't pay enough attention to the latest edit of the existing answer from @ranjandas and the following comments. My first solution is almost similar. I guess you are more interested by the second one.
Here are 2 different ways to achieve your requirement.
The first solution uses only filters available in ansible by default:
rejectattryou already mentionned and its counterpartselectattr. The idea is to add two lists. The first one is made by selecting all dicts not having thetypeatttribute. The second one is made by selecting dict having thetypeattribute and rejecting those where it equalsspecial.For the second solution, I used the
json_queryfilter which requirespip install jmespathon the controller. As you can see below it is much more compact.
The choice is yours !
The demo playbook:
---
- name: Show not so special items
hosts: localhost
gather_facts: false
vars:
list_of_dicts:
- name: Item1
- name: Item2
type: special
- name: Item3
- name: Item4
type: small
tasks:
- name: Use select/rejectattr
debug:
msg: >-
{{
(list_of_dicts | selectattr('type', 'undefined') | list)
+
(list_of_dicts | selectattr('type', 'defined') | rejectattr('type', 'eq', 'special') | list)
}}
- name: Use json_query
vars:
query: "[?type != 'special']"
debug:
msg: "{{ list_of_dicts | json_query(query) | list }}"
Which gives:
PLAY [Show not so special items] **********************************************************************************************************************************************************************************
TASK [Use select/rejectattr] **************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
{
"name": "Item1"
},
{
"name": "Item3"
},
{
"name": "Item4",
"type": "small"
}
]
}
TASK [Use json_query] *********************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
{
"name": "Item1"
},
{
"name": "Item3"
},
{
"name": "Item4",
"type": "small"
}
]
}
PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
You should use rejectattr to reject items that has type undefined and use selectattr to select the items that are equalto special.
{{ list_of_dicts | rejectattr("type", "undefined") | selectattr("type", "equalto", "special") | list }}
edit:
How about combining two lists like given below? I don't know whether this is the best possible way, but it works.
{{ list_of_dicts | selectattr("type", "undefined") | list }} + {{ list_of_dicts | rejectattr("type", "undefined") | rejectattr("type", "equalto", "special") | list}}
Is
selectattrfilter expecting all the dicts in the list to have the same keys?
More precisely, it is expecting all dicts in the list to have the attribute you are selecting on. If not all dict in the list have it, you will have to first filter out the items where it is not defined. This can be done with selectattr as well. (thanks @Randy for making this clearer since my initial answer).
In your situation, the json_query filter (which implements jmespath) can also do the job in sometimes a more compact manner. But it is not a core filter and requires to have the community.general collection installed.
Here are a few examples taken from your above requirements solved with both core filters and json_query solutions.
The playbook:
---
- name: "Filter data with core filters or json query"
hosts: "localhost"
gather_facts: false
vars:
# Your initial data on a single line for legibility
test_var: [{"vm":"vm1","ip":"10.10.10.1"},{"vm":"vm2","ip":"10.10.10.2"},{"test_vm":"something","process_1":"X","process_2":"Y","process_3":"Z"},{"another_vm":"something_other"}]
tasks:
- name: Get objects having vm==vm1
vars:
msg: |-
With core filters: {{ test_var | selectattr('vm', 'defined') | selectattr('vm', '==', 'vm1') | list }}
With json_query: {{ test_var | json_query("[?vm=='vm1']") | list }}
debug:
msg: "{{ msg.split('\n') }}"
- name: Get all objects having vm attribute
vars:
msg: |-
With core filters: {{ test_var | selectattr('vm', 'defined') | list }}
With json_query: {{ test_var | json_query("[?vm]") | list }}
debug:
msg: "{{ msg.split('\n') }}"
- name: Get all objects having process_2 attribute
vars:
msg: |-
With core filters: {{ test_var | selectattr('process_2', 'defined') | list }}
With json_query: {{ test_var | json_query("[?process_2]") | list }}
debug:
msg: "{{ msg.split('\n') }}"
- name: Get only a list of process_2 attributes
vars:
msg: |-
With core filters: {{ test_var | selectattr('process_2', 'defined') | map(attribute='process_2') | list }}
With json_query: {{ test_var | json_query("[].process_2") | list }}
debug:
msg: "{{ msg.split('\n') }}"
which gives:
PLAY [Filter data with core filters or json query] *********************************************************************
TASK [Get objects having vm==vm1] *********************************************************************
ok: [localhost] => {
"msg": [
"With core filters: [{'vm': 'vm1', 'ip': '10.10.10.1'}]",
"With json_query: [{'vm': 'vm1', 'ip': '10.10.10.1'}]"
]
}
TASK [Get all objects having vm attribute] *********************************************************************
ok: [localhost] => {
"msg": [
"With core filters: [{'vm': 'vm1', 'ip': '10.10.10.1'}, {'vm': 'vm2', 'ip': '10.10.10.2'}]",
"With json_query: [{'vm': 'vm1', 'ip': '10.10.10.1'}, {'vm': 'vm2', 'ip': '10.10.10.2'}]"
]
}
TASK [Get all objects having process_2 attribute] *********************************************************************
ok: [localhost] => {
"msg": [
"With core filters: [{'test_vm': 'something', 'process_1': 'X', 'process_2': 'Y', 'process_3': 'Z'}]",
"With json_query: [{'test_vm': 'something', 'process_1': 'X', 'process_2': 'Y', 'process_3': 'Z'}]"
]
}
TASK [Get only a list of process_2 attributes] *********************************************************************
ok: [localhost] => {
"msg": [
"With core filters: ['Y']",
"With json_query: ['Y']"
]
}
PLAY RECAP *********************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
To complement this edit of Zeitounator's answer:
More precisely, it is expecting all dicts in the list to have the attribute you are selecting on.
It is not 100% true for all filter functions, to select objects by an attribute not defined by all elements:
{{ test_var | selectattr('vm','defined') |selectattr('vm','equalto','vm1') | list }}