🎯 Filtering Data in Ansible: selectattr and map(attribute)

When working with lists of dictionaries in Ansible, filtering and extracting specific values is a common requirement. Jinja2 provides two powerful filters to accomplish this:

  • selectattr → Filters the list based on a condition.
  • map(attribute) → Extracts a specific field from the filtered result.

In this article, you'll learn:

  • ✅ How to filter lists of dictionaries in Ansible using selectattr
  • ✅ How to extract specific values using map(attribute)
  • ✅ How to handle missing values safely using default()

📌 Understanding selectattr and map(attribute)

Before jumping into Ansible playbooks, let's break down these Jinja2 filters.

✅ selectattr('name', 'equalto', search_name')

  • Filters a list of dictionaries to select only the ones where name == search_name.

✅ map(attribute='folder')

  • Extracts the folder field from the filtered result.

✅ Example Syntax

{{ variable | selectattr('name', 'equalto', search_name) | map(attribute='folder') | list }}
  • selectattr filters the list where name equals search_name.
  • map(attribute='folder') extracts only the folder values.
  • list ensures the result is returned as a list.

🔥 Example Use Case

Scenario

You have a list of users and their home directories (folder). You want to search for a specific user and get their folder path.

Example Data

variable:
  - name: alice
    folder: /home/alice
  - name: bob
    folder: /home/bob
  - name: charlie
    folder: /home/charlie

Using selectattr and map(attribute) in Ansible

- name: Search for a name and get its folder
  hosts: localhost
  gather_facts: no
  vars:
    variable:
      - name: alice
        folder: /home/alice
      - name: bob
        folder: /home/bob
      - name: charlie
        folder: /home/charlie
    search_name: alice
  tasks:
    - name: Get folder for a specific user
      debug:
        msg: "{{ variable | selectattr('name', 'equalto', search_name) | map(attribute='folder') | list }}"

🎯 Expected Output

When search_name: alice, the output will be:

TASK [Get folder for a specific user] *********************************************
ok: [localhost] => {
    "msg": [
        "/home/alice"
    ]
}

When search_name: bob, the output will be:

TASK [Get folder for a specific user] *********************************************
ok: [localhost] => {
    "msg": [
        "/home/bob"
    ]
}

🔹 Getting a Single Value Instead of a List

By default, the output is a list with one value. If you need only the string value, add .0:

- name: Get a single folder for a user
  debug:
    msg: "{{ (variable | selectattr('name', 'equalto', search_name) | map(attribute='folder') | list).0 }}"

📌 Expected Output

TASK [Get a single folder for a user] *********************************************
ok: [localhost] => {
    "msg": "/home/alice"
}

🚨 Handling Missing Values Gracefully

If the search_name does not exist in the list, you may encounter an error. To prevent this, use default():

- name: Get folder safely
  debug:
    msg: "{{ (variable | selectattr('name', 'equalto', search_name) | map(attribute='folder') | list | default(['/not-found'])).0 }}"

📌 Expected Output When search_name is Missing

TASK [Get folder safely] *********************************************
ok: [localhost] => {
    "msg": "/not-found"
}

✅ Summary Table

MethodOutput
`list`
.0"/home/alice"
default(['/not-found'])"/not-found" if no match

🚀 Why Use This Approach?

✔ Filters data dynamically
✔ Extracts only necessary values
✔ Handles missing values safely
✔ Works efficiently with lists of dictionaries

These Jinja2 filters are invaluable when working with structured data in Ansible playbooks!