I have some JSON output I need to loop through. It's basically a list within a dictionary within a list, etc. Here's an example:
{
"results": [
{
"children": {
"attachment": {
"results": [
{
"history": {},
"title": "SomeTitle"
}
]
}
}
}
]
}
I need to iterate through the second results
list (with the history
and title
, etc attributes) but I don't know how to get past the children
attribute. Here's the filter I've tried:
results | map(attribute='children').attachment.results
It throws an error that the .attachment.results
doesn't belong after map()
. So what's the right way to accomplish this?
Use the lookup plugin subelements. How exactly you can use it depends on what attributes can change.
results1:
- children:
attachment:
results:
- history: {}
title: SomeTitle
- future: {}
title: OtherTitle
the task
- debug:
msg: "{{ item }}"
loop: "{{ results1|subelements('children.attachment.results') }}"
loop_control:
label: "{{ item.0.keys()|first }}"
gives
TASK [debug] **********************************************************************************
ok: [localhost] => (item=children) =>
msg:
- children:
attachment:
results:
- history: {}
title: SomeTitle
- future: {}
title: OtherTitle
- history: {}
title: SomeTitle
ok: [localhost] => (item=children) =>
msg:
- children:
attachment:
results:
- history: {}
title: SomeTitle
- future: {}
title: OtherTitle
- future: {}
title: OtherTitle
results2:
- parents:
attachment:
results:
- history: {}
title: SomeTitle
- future: {}
title: OtherTitle
- children:
attachment:
results:
- history: {}
title: SomeTitle
- future: {}
title: OtherTitle
In this case, convert the list to a dictionary
results2_keys: "{{ results2|json_query('[][keys(@)]')|flatten(2) }}"
results2_vals: "{{ results2|json_query('[].*.*.results')|flatten(2) }}"
results2_dict: "{{ dict(results2_keys|zip(results2_vals)) }}"
gives
results2_dict:
children:
- history: {}
title: SomeTitle
- future: {}
title: OtherTitle
parents:
- history: {}
title: SomeTitle
- future: {}
title: OtherTitle
Use this dictionary to iterate subelements
- debug:
msg: "{{ item }}"
loop: "{{ results2_dict|dict2items|subelements('value') }}"
loop_control:
label: "{{ item.0.key }}"
gives
TASK [debug] **********************************************************************************
ok: [localhost] => (item=parents) =>
msg:
- key: parents
value:
- history: {}
title: SomeTitle
- future: {}
title: OtherTitle
- history: {}
title: SomeTitle
ok: [localhost] => (item=parents) =>
msg:
- key: parents
value:
- history: {}
title: SomeTitle
- future: {}
title: OtherTitle
- future: {}
title: OtherTitle
ok: [localhost] => (item=children) =>
msg:
- key: children
value:
- history: {}
title: SomeTitle
- future: {}
title: OtherTitle
- history: {}
title: SomeTitle
ok: [localhost] => (item=children) =>
msg:
- key: children
value:
- history: {}
title: SomeTitle
- future: {}
title: OtherTitle
- future: {}
title: OtherTitle
Example of a complete playbook for testing
- hosts: localhost
vars:
results1:
- children:
attachment:
results:
- history: {}
title: SomeTitle
- future: {}
title: OtherTitle
results2:
- parents:
attachment:
results:
- history: {}
title: SomeTitle
- future: {}
title: OtherTitle
- children:
attachment:
results:
- history: {}
title: SomeTitle
- future: {}
title: OtherTitle
results2_keys: "{{ results2|json_query('[][keys(@)]')|flatten(2) }}"
results2_vals: "{{ results2|json_query('[].*.*.results')|flatten(2) }}"
results2_dict: "{{ dict(results2_keys|zip(results2_vals)) }}"
tasks:
- debug:
msg: "{{ item }}"
loop: "{{ results1|subelements('children.attachment.results') }}"
loop_control:
label: "{{ item.0.keys()|first }}"
- debug:
var: results2_dict
- debug:
msg: "{{ item }}"
loop: "{{ results2_dict|dict2items|subelements('value') }}"
loop_control:
label: "{{ item.0.key }}"