netv
netv

Reputation: 185

How to remove null and replace with a string value in ansible

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

Answers (3)

Vladimir Botka
Vladimir Botka

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

Zeitounator
Zeitounator

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

Related Questions