Reputation: 185
How to remove null
and replace with a string novlaue
?
I have below output stored in variable out1
{
"out1": [
[
{
"destination": "dest-a",
"interface": "e1/1",
"metric": "10",
"name": "A"
},
{
"destination": "dest-b",
"interface": "e1/2",
"metric": "10",
"name": "B"
},
{
"destination": "dest-c",
"interface": null,
"metric": "10",
"name": "C"
},
{
"destination": "dest-d",
"interface": null,
"metric": "10",
"name": "B"
}
]
]
}
I have a json_query
in my code:
- debug: msg="{{out1 |json_query(myquery)}}"
vars:
myquery: "[].{dest: destination ,int: interface}"
register: out2
Above code will print the following:
{
"msg": [
{
"dest": "dest-a",
"int": "e1/1"
},
{
"dest": "dest-b",
"int": "e/12"
},
{
"dest": "dest-c",
"int": null
},
{
"dest": "dest-d",
"int": null
}
]
}
I want to replace or remove null
with the string novalue
.
I looked into some posts and found default("novalue")
can do the trick but in my case it is not working. I tried following added default("novalue")
to my debug
task, but I am getting an error.
I am sure that the error resides in myquery
, the way I interpret/understand default()
might be wrong and might be used wrongly.
Can anyone help me here please?
- debug: msg="{{out1 |json_query(myquery)}}"
vars:
myquery: "[].{dest: destination ,int: interface|default("novalue")}"
register: out2
Upvotes: 2
Views: 2164
Reputation: 67959
Q: "How to remove 'null' and replace it with a string 'no value'?"
update
A: Use Jinja
out2: |
{% filter from_yaml %}
{% for i in out1 %}
- {% for j in i %}
- {% if j.interface == None -%}
{{ j|combine({'interface': 'no value'}) }}
{% else -%}
{{ j }}
{% endif -%}
{% endfor %}
{% endfor %}
{% endfilter %}
gives
out2:
- - {destination: dest-a, interface: e1/1, metric: '10', name: A}
- {destination: dest-b, interface: e1/2, metric: '10', name: B}
- {destination: dest-c, interface: no value, metric: '10', name: C}
- {destination: dest-d, interface: no value, metric: '10', name: B}
Example of a complete playbook for testing
- hosts: localhost
vars:
out1:
- - {destination: dest-a, interface: e1/1, metric: '10', name: A}
- {destination: dest-b, interface: e1/2, metric: '10', name: B}
- {destination: dest-c, interface: null, metric: '10', name: C}
- {destination: dest-d, interface: null, metric: '10', name: B}
out2: |
{% filter from_yaml %}
{% for i in out1 %}
- {% for j in i %}
- {% if j.interface == None -%}
{{ j|combine({'interface': 'no value'}) }}
{% else -%}
{{ j }}
{% endif -%}
{% endfor %}
{% endfor %}
{% endfilter %}
tasks:
- debug:
var: out2|to_yaml
origin
A: The variable out1 is a list of lists. Let's iterate it and create out2 with null replaced by 'no value' string. In each loop create the list of interface attributes with null replaced. Combine this list with the item and add it to the new list. The task below gives the same result
- set_fact:
out2: "{{ out2|d([]) + [item|zip(_item)|map('combine')] }}"
loop: "{{ out1 }}"
vars:
_item: "{{ item|json_query(_query) }}"
_query: |
[].{interface: not_null(interface, 'no value')}
Upvotes: 1
Reputation: 39069
Otherwise, with another JMESPath expression to achieve this, you can use an or expression ||
, that will display the value of interface
or a string that you are free to define.
So, given your JSON:
[
{
"destination": "dest-a",
"interface": "e1/1",
"metric": "10",
"name": "A"
},
{
"destination": "dest-b",
"interface": "e1/2",
"metric": "10",
"name": "B"
},
{
"destination": "dest-c",
"interface": null,
"metric": "10",
"name": "C"
},
{
"destination": "dest-d",
"interface": null,
"metric": "10",
"name": "B"
}
]
And the JMESPath query
[].{dest: destination ,int: interface || 'novalue'}
This yields
[
{
"dest": "dest-a",
"int": "e1/1"
},
{
"dest": "dest-b",
"int": "e1/2"
},
{
"dest": "dest-c",
"int": "novalue"
},
{
"dest": "dest-d",
"int": "novalue"
}
]
And your task ends up being:
- debug:
msg: "{{ out1 | json_query(_query) }}"
vars:
_query: "[].{dest: destination ,int: interface || 'novalue')}"
register: out2
Upvotes: 3
Reputation: 44595
You are using the jinja2 default
filter inside a jmespath (i.e. json_query) expression. This can't work.
You can use the jmespath function not_null
in this case
The playbook:
---
- hosts: localhost
gather_facts: false
vars:
"out1": [
[
{
"destination": "dest-a",
"interface": "e1/1",
"metric": "10",
"name": "A"
},
{
"destination": "dest-b",
"interface": "e1/2",
"metric": "10",
"name": "B"
},
{
"destination": "dest-c",
"interface": null,
"metric": "10",
"name": "C",
},
{
"destination": "dest-d",
"interface": null,
"metric": "10",
"name": "B"
}
]
]
tasks:
- debug:
msg: "{{ out1 | json_query(myquery) }}"
vars:
myquery: >-
[].{dest: destination ,int: not_null(interface, 'no value')}
Gives:
PLAY [localhost] **************************************************************************************************************************************************************************************************************
TASK [debug] ******************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
{
"dest": "dest-a",
"int": "e1/1"
},
{
"dest": "dest-b",
"int": "e1/2"
},
{
"dest": "dest-c",
"int": "no value"
},
{
"dest": "dest-d",
"int": "no value"
}
]
}
PLAY RECAP ********************************************************************************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Upvotes: 2