Is selectattr filter 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   
Answer from Zeitounator on Stack Overflow
Discussions

python - Ansible - how to use selectattr with yaml of different keys - Stack Overflow
im pulling my hairs trying to do a simple thing (i thought it should be easy) with parsing a yaml and filtering for some key in Ansible. My yaml file looks like this: --- - vm: "vm1" ip: 10.10... More on stackoverflow.com
🌐 stackoverflow.com
Ansible selectattr and map with optional fields - Stack Overflow
I am trying create an ansible playbook to set up multiple nodes. In my variables I have a the following structure: nodes: - nodename: foonode othervalue: foo booleanvalue: true - nodename: barnode othervalue: bar · The booleanvalue is optional and shoutd default to false. Later it might be possible to have more optional values. For now I only want to use the optional boolean value. - name: "Debug" debug: msg: "Do something useful here" when: when: nodes | selectattr... More on stackoverflow.com
🌐 stackoverflow.com
jinja2 - Passing a var into a selectattr statment in Ansible - Stack Overflow
I am looping through a dict "aws_ec2_volums_setting" and i am trying to pass the loop variable item.id to a "selectattr" statement to get a list that meets the criteria. - name: Set Filters se... More on stackoverflow.com
🌐 stackoverflow.com
ansible - Conditional set_fact only with selectattr? - Stack Overflow
I am trying to use set_fact, but only when an item is defined. I'm having trouble figuring out how to do this. Playbook: --- - hosts: localhost vars: apps: - name: app1 ... More on stackoverflow.com
🌐 stackoverflow.com
April 4, 2020
🌐
Middleware Inventory
middlewareinventory.com › blog › ansible-selectattr-example
Ansible selectattr Example - Filter dictionary and select matching item
February 24, 2024 - Ansible Selectattr example. Filter and Select items from Ansible dictionary using selectattr example. How to select attributes from Ansible dictorinary.
Top answer
1 of 2
8

Is selectattr filter 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   
2 of 2
8

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 }} 
🌐
Oznetnerd
oznetnerd.com › 2017 › 04 › 18 › jinja2-selectattr-filter
Jinja2 selectattr() Filter - OzNetNerd.com
April 17, 2017 - As per the documentation: “selectattr() filters a sequence of objects by applying a test to the specified attribute of each object, and only selecting the objects with the test succeeding. If no test is specified, the attribute’s value will be evaluated as a boolean.“ Example #1 This ...
🌐
AnsiblePilot
ansiblepilot.com › articles › filtering-data-in-ansible-selectattr-and-map
Filtering Data in Ansible: selectattr and map(attribute)
January 29, 2025 - msg: "{{ (variable | selectattr('name', 'equalto', search_name) | map(attribute='folder') | list).0 }}"
🌐
0xf8
0xf8.org › 2021 › 03 › filtering-with-ansibles-selectattr-rejectattr-when-the-tested-attribute-can-be-absent
Filtering with Ansible’s selectattr()/rejectattr() when the tested attribute can be absent – 0xf8.org
March 19, 2021 - {{ fruit | selectattr('or', 'origin', 'not', 'defined', 'origin', 'equalto', 'exotic') }} # selectattr/rejectattr do not support brackets either {{ fruit | selectattr('or'(('origin', 'not', 'defined'), ('origin', 'equalto', 'exotic'))) }}
🌐
Ansible
docs.ansible.com › projects › ansible › latest › playbook_guide › playbooks_tests.html
Tests — Ansible Community Documentation
vars: lacp_groups: - master: lacp0 network: 10.65.100.0/24 gateway: 10.65.100.1 dns4: - 10.65.100.10 - 10.65.100.11 interfaces: - em1 - em2 - master: lacp1 network: 10.65.120.0/24 gateway: 10.65.120.1 dns4: - 10.65.100.10 - 10.65.100.11 interfaces: - em3 - em4 tasks: - debug: msg: "{{ (lacp_groups|selectattr('interfaces', 'contains', 'em1')|first).master }}"
Find elsewhere
🌐
Packetswitch
packetswitch.co.uk › ansible-selectattr-filter
How to use Ansible 'selectattr' Filter?
September 21, 2024 - 'selectattr' filter is a feature within Jinja2 that enables filtering a list of objects based on an attribute's presence or value. Let's look at a few examples to better understand this filter.
🌐
Stack Overflow
stackoverflow.com › questions › 65493438 › ansible-selectattr-and-map-with-optional-fields
Ansible selectattr and map with optional fields - Stack Overflow
In my variables I have a the following structure: nodes: - nodename: foonode othervalue: foo booleanvalue: true - nodename: barnode othervalue: bar · The booleanvalue is optional and shoutd default to false.
🌐
Tailored Cloud
tailored.cloud › home › advanced list operations in ansible
Advanced list operations in Ansible. selectattr, sum, map and others.
March 16, 2018 - The problem can be solved with the following ansible code. Let’s first have a look and then I will explain it step by step: # file playbook.yml - hosts: all tasks: - set_fact: test_ip: "{{ interfaces | selectattr('name', 'match', 'eth[2-9]') | sum(attribute='ips', start=[]) | selectattr('owner', 'equalto', 'TEST') | map(attribute='ip') | list | first | default('NOT_FOUND') }}" - debug: msg: "The TEST IP is {{ test_ip }}"
🌐
Linux Hint
linuxhint.com › ansible-selectattr-rejectattr
Ansible Selectattr/Rejectattr – Linux Hint
Each select attribute is used to perform testing on each object that is a defined attribute and only picking those that pass the testing filters, is a succession of items. The result of the select attribute would be assessed as a boolean even though no test is defined in Ansible.
🌐
OneUptime
oneuptime.com › home › blog › how to use the selectattr and rejectattr filters in ansible
How to Use the selectattr and rejectattr Filters in Ansible
February 21, 2026 - When you have a list of dictionaries ... list based on the value of a specific attribute. The selectattr filter keeps items where an attribute passes a test, and rejectattr removes items where an attribute passes a test...
🌐
Medium
lucaberton.medium.com › filter-a-list-by-its-attributes-ansible-selectattr-filter-66881fe8a825
Filter A List By Its Attributes — Ansible selectattr filter | by Luca Berton | Medium
July 28, 2023 - Filters a sequence of objects by applying a test to the specified attribute of each object, and only selecting the objects with the test succeeding. If no test is specified, the attribute’s value will be evaluated as a boolean.
🌐
Ansiblebyexample
ansiblebyexample.com › home › articles › playbooks › filter a list by its attributes - ansible selectattr filter
Filter A List By Its Attributes - Ansible selectattr filter
June 24, 2024 - Filters a sequence of objects by applying a test to the specified attribute of each object, and only selecting the objects with the test succeeding. If no test is specified, the attribute's value will be evaluated as a boolean.
🌐
Google Groups
groups.google.com › g › ansible-project › c › h3ITuANKl6s
selectattr with ansible
to ansible...@googlegroups.com · Hi, I have a list like below, and I need to select the sequence which has "name" attribute equal to "lo0". I use this selectattr statement {% set lo0 = interfaces|selectattr("name", "equalto", lo0) | first%} But while running the playbook throws me an error {'msg': "TemplateRuntimeError: no test named 'equalto'", 'failed': True} interfaces: - name: lo0 unit0: ip_primary: 1.1.1.1 ip_secondary: 2.2.2.2 unit1: ip_primary: 3.3.3.3 ip_secondary: 4.4.4.4 - name: xyz unit0: ip_primary: 9.9.9.9 Jinja2 version 2.7.3.