I make an API call in ansible and analyse the response. A repro:
---
- hosts: localhost
gather_facts: false
vars:
response: {
"results": [
{
"item": "server1",
"json": {
"data": null, # <----- here's the problem
"ok": true
},
"status": 200
},
{
"item": "server2",
"json": {
"data": [
{
"id": 7,
"name": "Production5"
}
],
"ok": true
},
"status": 200
}
]
}
tasks:
- debug:
msg: "{{ response.results | community.general.json_query(_query) }}"
vars:
_query: "[].json.data[*].id | []"
Which yields:
TASK [debug] *********************************************
ok: [localhost] => {
"msg": [
7
]
}
But I actually need:
TASK [debug] *********************************************
ok: [localhost] => {
"msg": [
null, # <-----
7
]
}
I want to keep the null
so the input and output arrays have the same length, as this is important in future tasks.
I tried converting the null without success, e.g.: ([].json.data || [])[*].id
and not_null([].json.data, '[]')[*].id
.
The filter json_query is not capable of doing this, I'm afraid. Try Jinja instead
result: |
{% filter from_yaml %}
{% for i in response.results|map(attribute='json.data') %}
- {{ i.0.id|default('null') }}
{% endfor %}
{% endfilter %}
gives what you want
result:
- null
- 7
Optionally, use json_query, create the lists of values, and map the value. The below expression gives the same result
result: "{{ response.results|
json_query('[].[json.data[0].id, item]')|
map('first') }}"
- hosts: localhost
vars:
response:
results:
- item: server1
json:
data: null
ok: true
status: 200
- item: server2
json:
data:
- {id: 7, name: Production5}
ok: true
status: 200
result1: |
{% filter from_yaml %}
{% for i in response.results|map(attribute='json.data') %}
- {{ i.0.id|default('null') }}
{% endfor %}
{% endfilter %}
result2: "{{ response.results|
json_query('[].[json.data[0].id, item]')|
map('first') }}"
tasks:
- debug:
var: result1
- debug:
var: result2