G_G
G_G

Reputation: 153

jinja2 turning lists into strings even when from_json is being used

I am trying to run a nested for loop in order to retrieve a nested value. I would like to retrieve some_value_4 when some_value_3 matches a criteria that's predefined.

{
  "some_dict": {
    "some_key_0": "value_0",
    "some_key_1": "value_1"
  },
  "testval_dict": {
    "test_key_0": "some_value_0",
    "test_key_1": "some_value_1",
    "test_key_2": "some_value_2",
    "test_key_3": "some_value_3",
    "test_key_4": "some_value_4"
  }
}

The playbook:

- hosts: localhost
  tasks:
   
   - set_fact:
       mydict: "{{ lookup('file', '/tmp/file.json' ) | from_json }}"

   - debug:
       msg: |
            "{% for item in mydict %}
             {{ item }}
             {% endfor %}"

when run, it alreay looks like dict names are treated as string and nothing more:

ansible-playbook /tmp/test_playbook.yml -c local -i ', localhost'
TASK [debug] ******************************************************************
ok: [localhost] => {}

MSG:

" somee_dict
  testval_dict
 "

Then when I add an itme.key to the debug task, the playbook fails:

MSG:

The task includes an option with an undefined variable. The error was: 'str object' has no attribute 'value'

Thank you.

edit for clarification In the real example, I will not know the names of the dicts, so I cannot use some_dict or testval_dict, that is why I'm trying to go over this data source in an item.key or item.value form.

Upvotes: 1

Views: 1763

Answers (2)

seshadri_c
seshadri_c

Reputation: 7340

If you need to loop over the dictionary, you can use with_dict loop functionality. This way, if you loop over mydict and get item.key you will get somee_dict and testval_dict.

  tasks:
  - set_fact:
      mydict: "{{ lookup('file', '/tmp/file.json')|from_json }}"
  # This will get the top level dictionaries somee_dict and testval_dict
  - debug:
      var: item.key
    with_dict: "{{ mydict }}"

And if you get item.value of mydict you will get the sub-dictionary:

  - debug:
      var: item.value
    with_dict: "{{ mydict }}"

Will produce (showing output only for testval_dict):

    "item.value": {
        "test_key_0": "some_value_0",
        "test_key_1": "some_value_1",
        "test_key_2": "some_value_2",
        "test_key_3": "some_value_3",
        "test_key_4": "some_value_4"
    }

Upvotes: 0

Vladimir Botka
Vladimir Botka

Reputation: 68024

Q: "{% for item in mydict %} ... dict names are treated as string and nothing more."

A: This is correct. A dictionary, when evaluated as a list, returns the list of its keys. See some examples below

    - debug:
        msg: "{{ mydict.keys()|list }}"
    - debug:
        msg: "{{ mydict[item] }}"
      loop: "{{ mydict.keys()|list }}"
    - debug:
        msg: "{{ mydict|difference(['testval_dict']) }}"

give

  msg:
  - some_dict
  - testval_dict
  msg:
    some_key_0: value_0
    some_key_1: value_1

  msg:
    test_key_0: some_value_0
    test_key_1: some_value_1
    test_key_2: some_value_2
    test_key_3: some_value_3
    test_key_4: some_value_4
  msg:
  - some_dict

See How to iterate through a list of dictionaries in Jinja template?

Upvotes: 1

Related Questions