Ansible – Reject Items from List of Dicts with Specific Attribute in Jinja2

ansiblejinja2

I have a list of dicts like this:

list_of_dicts:
  - name: Item1
  - name: Item2
    type: special
  - name: Item3
  - name: Item4
    type: small

As you can see, not all items have a type attribute. Context: If no type attribute is set, that means the item is of the default type.

I would like to select all items which are NOT of type special.

I've tried this: list_of_dicts | rejectattr('type', 'equalto', 'special')

Unfortunately, this fails with a AnsibleUndefinedVariable: 'dict object' has no attribute 'type' error because some of the items do not have a type.

What is a good way to solve this?

Best Answer

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.

  1. The first solution uses only filters available in ansible by default: rejectattr you already mentionned and its counterpart selectattr. The idea is to add two lists. The first one is made by selecting all dicts not having the type atttribute. The second one is made by selecting dict having the type attribute and rejecting those where it equals special.

  2. For the second solution, I used the json_query filter which requires pip install jmespath on 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