1

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.

G_G
  • 133
  • 3
  • 11
  • thank you. yes I don't have the conditionals as I wasn't even being successful with getting into the next level down the dict whatsoever, so I kept the question simple. :) I am able to do so using your example. I cannot treat this in a form of `{{item.key}}` or `{{item.value}}`, am I doomed here and jinja2 will keep only getting strings ? – G_G Jan 17 '21 at 17:39
  • Re-adding my previous comment. You should be able to access the values of `testval_dict` by `mydict.testval_dict.test_key_X` without looping. – seshadri_c Jan 17 '21 at 17:41
  • I quite foolishly edit a comment left by another user :(, the advice was to use `mydict.testval_dict` in order get one level further in the dict. – G_G Jan 17 '21 at 17:42
  • sorry about that @seshadri_c , I didn't have enough coffee yet, obviously. – G_G Jan 17 '21 at 17:43
  • @seshadri_c, I think I have to loop here, as I _do not_ know what would be the name of either of dicts, so I must ignore them and iterate within them, does that make sense ? – G_G Jan 17 '21 at 17:45

2 Answers2

1

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?

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

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"
    }
seshadri_c
  • 6,906
  • 2
  • 10
  • 24
  • correct, I've tried that, and it leads me to use `with_dict.testval_dict`, and then again I muse hardoce the names of the dicts. perhaps there's no escaping this and I'm trying what can't be done. – G_G Jan 17 '21 at 18:07
  • Yes, that seems to be true. As accessing values in a dictionary without knowing the keys even without nesting is quite difficult. – seshadri_c Jan 17 '21 at 18:14