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 blog post does a great job of demonstrating how to use selectattr( ) . Let’s take a look at how it works.

First, the author creates a “users” dictionary:

---
users:
  - name: john
    email: john@example.com
  - name: jane
    email: jane@example.com
  - name: fred
    email: fred@example.com
    password: 123!abc

Next, the author runs the following:

- set_fact:
    emails: "{{ users | selectattr('password', 'undefined') | map(attribute='email') | list }}"

What we see here is:

  1. the “users” dictionary is being passed to the selectattr( )  filter.
  2. The selectattr() filter will cycle through all of the dictionaries (also known as objects) inside of “users”, looking for which ones do and do not have the “password” attribute specified.
  3. Because the ‘undefined’ Test has been passed as a parameter, only the objects which do not have a “password” attribute defined will be recorded.
  4. The map( ) filter is then used to return the “email” attribute of all objects that were recorded in the previous step.

Example #2

This StackOverflow response also has some great examples of how selectattr( )  can be used with both Jinja (equalto( ) ) and Ansible (match( )  and search( ) ) tests.

Using this dictionary:

- hosts: localhost
  connection: local
  gather_facts: no
  vars:
    network:
      addresses:
        private_ext:
          - type: fixed
            addr: 172.16.2.100
        private_man:
          - type: fixed
            addr: 172.16.1.100
          - type: floating
            addr: 10.90.80.10

We can obtain the “floating” value using any one of following filters:

- debug: msg={{ network.addresses.private_man | selectattr("type", "equalto", "floating") | map(attribute='addr') | list }}
- debug: msg={{ network.addresses.private_man | selectattr("type", "match", "^floating$") | map(attribute='addr') | list }}
- debug: msg={{ network.addresses.private_man | selectattr("type", "search", "^floating$") | map(attribute='addr') | list }}

The above lines result in the following output:

TASK [debug] *******************************************************************
ok: [localhost] => {
    "msg": [
        "10.90.80.10"
    ]
}

TASK [debug] *******************************************************************
ok: [localhost] => {
    "msg": [
        "10.90.80.10"
    ]
}

TASK [debug] *******************************************************************
ok: [localhost] => {
    "msg": [
        "10.90.80.10"
    ]
}

As always, if you have any questions or have a topic that you would like me to discuss, please feel free to post a comment at the bottom of this blog entry, e-mail at will@oznetnerd.com, or drop me a message on Reddit (OzNetNerd).

Note: The opinions expressed in this blog are my own and not those of my employer.

Leave a comment