6

As the title suggest i want to loop over an existing dictionary and change some values, based on the answer to this question i came up with the code below but it doesn't work as the values are unchanged in the second debug call, I'm thinking it is because in the other question they are creating a new dictionary from scratch, but I've also tried it without the outer curly bracket which i would have thought would have caused it to change the existing value.

- set_fact:
  uber_dict:
    a_dict:
      some_key: "abc"
      another_key: "def"
    b_dict:
      some_key: "123"
      another_key: "456"

- debug: var="uber_dict"

- set_fact: "{ uber_dict['{{ item }}']['some_key'] : 'xyz' }"
  with_items: "{{ uber_dict }}"

- debug: var="uber_dict"
Snipzwolf
  • 533
  • 1
  • 8
  • 22
  • You cannot. Define a whole new `uber_dict`. – techraf Feb 16 '18 at 11:22
  • @techraf I knew you couldn't merge hash's passed in (although i think there is a option now to do that) but i didn't think that applied altering them too, thought of it just after posting but maybe i could do something with the [combine](http://docs.ansible.com/ansible/latest/playbooks_filters.html#combining-hashes-dictionaries) filter but i suspect it will be pretty ugly – Snipzwolf Feb 16 '18 at 11:32
  • Whatever you do, you must ...read my first comment. – techraf Feb 16 '18 at 11:32

1 Answers1

26

You can not change existing variable, but you can register new one with the same name.

Check this example:

---
- hosts: localhost
  gather_facts: no
  vars:
    uber_dict:
      a_dict:
        some_key: "abc"
        another_key: "def"
      b_dict:
        some_key: "123"
        another_key: "456"
  tasks:
    - set_fact:
        uber_dict: "{{ uber_dict | combine(new_item, recursive=true) }}"
      vars:
        new_item: "{ '{{ item.key }}': { 'some_key': 'some_value' } }"
      with_dict: "{{ uber_dict }}"
    - debug:
        msg: "{{ uber_dict }}"

Result:

ok: [localhost] => {
    "msg": {
        "a_dict": {
            "another_key": "def",
            "some_key": "some_value"
        },
        "b_dict": {
            "another_key": "456",
            "some_key": "some_value"
        }
    }
}
U880D
  • 8,601
  • 6
  • 24
  • 40
Konstantin Suvorov
  • 65,183
  • 9
  • 162
  • 193
  • had just be trying out the same thing, works perfectly for my use thanks. – Snipzwolf Feb 16 '18 at 11:43
  • 1
    Does this still work? I'm having the same issue, but using the above solution I seem to get an "ansible_facts" dictionary which contains my new dictionary, (i.e. it has the updated keys) but when I print my dictionary afterwards it returns as the original version (i.e. the original key-value pairs) – Conor Feb 14 '19 at 12:27
  • How can you do that if uber_dict is a list please ? – Loenix Oct 21 '19 at 09:27
  • 1
    i know it is an old question but i have similar problem and no answers on my question. What do we do if the values are nested and you need to change only them? With this approach i get overwritten target key, instead of only updated different values? – fixxxera Sep 01 '21 at 10:59