how to make the jinja2 generator comprehension work in ansible?

Viewed 1172

I have a list of nested dict. I would like to use jinja2 generator comprehension to create a list from it.

test_nested_dict_list:
  - foo:
    a:
      x: 1
      y: 2
    b: 2
  - bar:
    a:
      x: 2
      y: 4
    b: 4

- debug:
    msg: "{{(u.b for u in test_nested_dict_list if u.a.x == 1 ) | list}}"

this cause a error: {"msg": "template error while templating string: expected token ')', got 'for'. String: {{(u.b for u in test_nested_dict_list if u.a.x == 1 ) | list}}"}

2 Answers

JMESPath, the JSON query language used by the filter json_query is quite a powerful language that could help you achieve such thing.

There is actually one example in there documentation that looks pretty much like what you want to achieve.

So the whole logic just lays on the capability of the query language to look for nested data in order to select a node.
So, this syntax: [?a.x==`1`].b would equal to a logic like find all subelement having a.x == 1, then get me b out of it.

Given the playbook:

- hosts: localhost
  gather_facts: no
  vars:
    test_nested_dict_list:
      - foo:
        a:
          x: 1
          y: 2
        b: 2
      - bar:
        a:
          x: 2
          y: 4
        b: 4

  tasks:
    - debug: 
        msg: "{{ test_nested_dict_list | json_query('[?a.x==`1`].b') | list }}"

It gives the recap:

PLAY [localhost] *****************************************************************************************************************

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

PLAY RECAP ***********************************************************************************************************************
localhost  

Python code could be executed using shell module like so.

- shell: |
    print( list(u['b'] for u in {{test_nested_dict_list}} if u['a']['x'] == 1) )
  args:
    executable: /usr/bin/python
  register: result

- debug:
    msg: "{{ result.stdout }}"
Related