I'm trying to edit a dictionary in ansible with a one line json_query (and/or other filters), but something is wrong and I can't figure it out. I have this structure (with example data)
seinfeld:
- name: Jerry
jobs:
- comedian
friends:
- name: Elaine
- name: Kramer
- name: George
jobs:
- yankees
friends:
- name: Jerry
- name: Susan
And I need to create a new structure like this
new_list:
- main: Jerry
name: Elaine
- main: Jerry
name: Kramer
- main: George
name: Jerry
- main: George
name: Susan
The name
key is added to every element of friends
key and flatten it out to a new list.
I already made some progress mixing jmespath map
and merge
, but at least one key is always null or invalid, some of random tests are
[].merge({friends: friends},{main: name}) [*].map(&merge({main: name}, @), friends)
There are more options for getting the data. For example,
tmp: "{{ seinfeld | json_query('[].[name, friends[].name]') }}"
tmp: "{{ seinfeld | map(attribute='name') |
zip(seinfeld | map(attribute='friends')
| map('map', attribute='name')) }}"
give the same list
tmp:
- - Jerry
- - Elaine
- Kramer
- - George
- - Jerry
- Susan
Now, you would need to map the function product. Unfortunately, this is not possible. The filter json_query doesn't help you with the list of lists either. So, this is a dead end.
The only option is a Jinja template
new_list: |
{% filter from_yaml %}
{% for name in tmp %}
{% for friend in name.1 %}
- {main: {{ name.0 }}, name: {{ friend }}}
{% endfor %}
{% endfor %}
{% endfilter %}
gives what you want
new_list:
- main: Jerry
name: Elaine
- main: Jerry
name: Kramer
- main: George
name: Jerry
- main: George
name: Susan
But, you can easily iterate the list with subelements. For example,
- debug:
msg: "main: {{ item.0.name }}, name: {{ item.1.name }}"
loop: "{{ seinfeld | subelements('friends') }}"
gives (abridged)
msg: 'main: Jerry, name: Elaine'
msg: 'main: Jerry, name: Kramer'
msg: 'main: George, name: Jerry'
msg: 'main: George, name: Susan'
The decision of whether you need new_list is up to you.
Example of a complete playbook for testing
- hosts: localhost
vars:
seinfeld:
- name: Jerry
jobs:
- comedian
friends:
- name: Elaine
- name: Kramer
- name: George
jobs:
- yankees
friends:
- name: Jerry
- name: Susan
tmp1: "{{ seinfeld | json_query('[].[name, friends[].name]') }}"
tmp2: "{{ seinfeld | map(attribute='name') |
zip(seinfeld | map(attribute='friends')
| map('map', attribute='name')) }}"
new_list: |
{% filter from_yaml %}
{% for name in tmp1 %}
{% for friend in name.1 %}
- {main: {{ name.0 }}, name: {{ friend }}}
{% endfor %}
{% endfor %}
{% endfilter %}
tasks:
- debug:
var: tmp1
- debug:
var: tmp2
- debug:
var: new_list
- debug:
msg: "main: {{ item.0.name }}, name: {{ item.1.name }}"
loop: "{{ seinfeld | subelements('friends') }}"