1

I cannot manage to make json_query work, even with the simplest examples. I have a fact old_new_nodes like:

ok: [localhost] => {
    "msg": [
        {
            "id_new": 2430,
            "id_old": 2263
        },
        {
            "id_new": 2431,
            "id_old": 2283
        }
    ]
}

I want to save the id_new parameter whenever the id_old is equal to a certain value. I do:

- name: Get id of the new node
  set_fact:
    new_node_id: "{{ (old_new_nodes | first) |json_query('[?id_old==original_node.id].id_new') }}"

I have checked that original_node.id is 2263 so the expected result is 2430. Moreover, I have tried without the first and I still get [] as a result

Hector Esteban
  • 1,011
  • 1
  • 14
  • 29
  • `original_node.id` is inside the single quotes so it's being interpreted as a string instead of the value 2263. Once you fix that, remove the `first` and it should work. – Rickkwa Oct 03 '21 at 03:08

1 Answers1

1

A literal in JMESPath expression must be quoted. See Grammar

list-filter-expr  = expression comparator expression
comparator        = "<" / "<=" / "==" / ">=" / ">" / "!="
expression        =/ "*" / multi-select-list / multi-select-hash / literal
literal           = "`" json-value "`"

Unquoted literal causes the error bellow

    - debug:
        msg: "{{ old_new_nodes|json_query('[?id_old == 2263].id_new') }}"
   msg: |-
    JMESPathError in json_query filter plugin:
    invalid token: Parse error at column 12, token "2263" (NUMBER), for expression:
    "[?id_old == 2263].id_new"
                 ^

The query works as expected if you quote the literal

    - debug:
        msg: "{{ old_new_nodes|json_query('[?id_old == `2263`].id_new') }}"

gives

  msg:
  - 2430

If you want to put the searched value into a variable simplify the quotation of the query and put it into a variable too. The task below gives the same result

    - debug:
        msg: "{{ old_new_nodes|json_query(query) }}"
      vars:
        id: 2263
        query: '[?id_old == `{{ id }}`].id_new'

It's possible to iterate the list, e.g.

    - debug:
        msg: "{{ old_new_nodes|json_query(query) }}"
      loop: "{{ old_new_nodes|map(attribute='id_old')|list }}"
      vars:
        query: '[?id_old == `{{ item }}`].id_new'

gives

  msg:
  - 2430

  msg:
  - 2431

It'd be better to convert the list to a dictionary if you have to search it repeatedly, e.g.

    - set_fact:
        old_new: "{{ old_new_nodes|
                     items2dict(key_name='id_old', value_name='id_new') }}"

gives

  old_new:
    2263: 2430
    2283: 2431

This would make the searching both trivial and fast.

Vladimir Botka
  • 58,131
  • 4
  • 32
  • 63