# How to replace only a specific entry in a nested dictionary

**URL:** <https://forum.ansible.com/t/how-to-replace-only-a-specific-entry-in-a-nested-dictionary/38352>\
**Category:** Ansible Project\
**Created:** [August 18, 2023, 1:40pm UTC](https://forum.ansible.com/t/how-to-replace-only-a-specific-entry-in-a-nested-dictionary/38352 "2023-08-18T13:40:24Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![actionmystique](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/actionmystique/32/1678_2.png) [@actionmystique](https://forum.ansible.com/u/actionmystique)\
**Post date:** [August 18, 2023, 1:40pm UTC](https://forum.ansible.com/t/how-to-replace-only-a-specific-entry-in-a-nested-dictionary/38352/1 "2023-08-18T13:40:24Z")

</div>

The source nested dictionary is for instance the following:  
vpc:  
provider:

- net\_type: ‘db’  
net\_ipv4\_subnet: ‘10.0.0.0/16’  
net\_ipv6\_subnet: ‘FD00::/64’  
net\_id: 0  
nic\_ids:
- 1111111111
- 2222222222
- net\_type: ‘dns’  
net\_ipv4\_subnet: ‘10.1.0.0/16’  
net\_ipv6\_subnet: ‘FD01::/64’  
net\_id: 1  
nic\_ids:
- 3333333333
- 4444444444
- net\_type: ‘ns’  
net\_ipv4\_subnet: ‘10.2.0.0/16’  
net\_ipv6\_subnet: ‘FD02::/64’  
net\_id: 2  
nic\_ids:
- 5555555555
- 6666666666

We need to replace only the whole entry indexed by “net\_type: ‘dns’” with:

- net\_type: ‘dns’  
net\_ipv4\_subnet: ‘10.3.0.0/16’  
net\_ipv6\_subnet: ‘FD03::/64’  
net\_id: 3  
nic\_ids: 

so the result would look like:  
vpc:  
provider:

- net\_type: ‘db’  
net\_ipv4\_subnet: ‘10.0.0.0/16’  
net\_ipv6\_subnet: ‘FD00::/64’  
net\_id: 0  
nic\_ids:
- 1111111111
- 2222222222
- net\_type: ‘dns’  
net\_ipv4\_subnet: ‘10.3.0.0/16’  
net\_ipv6\_subnet: ‘FD03::/64’  
net\_id: 3  
nic\_ids: 
- net\_type: ‘ns’  
net\_ipv4\_subnet: ‘10.2.0.0/16’  
net\_ipv6\_subnet: ‘FD02::/64’  
net\_id: 2  
nic\_ids:
- 5555555555
- 6666666666

I’ve tried the following task using the **combine** filter:

- name: Combining 2 dictionaries with combine/list\_merge=‘replace’  
vars:  
vpc:  
provider:
- net\_type: ‘db’  
net\_ipv4\_subnet: ‘10.0.0.0/16’  
net\_ipv6\_subnet: ‘FD00::/64’  
net\_id: 0  
nic\_ids:
- 1111111111
- 2222222222
- net\_type: ‘dns’  
net\_ipv4\_subnet: ‘10.1.0.0/16’  
net\_ipv6\_subnet: ‘FD01::/64’  
net\_id: 1  
nic\_ids:
- 3333333333
- 4444444444
- net\_type: ‘ns’  
net\_ipv4\_subnet: ‘10.2.0.0/16’  
net\_ipv6\_subnet: ‘FD02::/64’  
net\_id: 2  
nic\_ids:
- 5555555555
- 6666666666  
net\_id: 3  
net\_ipv4\_subnet: ‘10.3.0.0/16’  
net\_ipv6\_subnet: ‘FD03::/64’  
new\_vpc: “{{ vpc | combine({‘provider’: [{‘net\_type’: ‘dns’, ‘net\_id’: net\_id, ‘net\_ipv4\_subnet’: net\_ipv4\_subnet, ‘net\_ipv6\_subnet’: net\_ipv6\_subnet, ‘nic\_ids’: }]}, recursive=True, list\_merge=‘replace’) }}”  
debug:  
msg: “{{ new\_vpc }}”

which unfortunately removes the other 2 entries:  
ok: [localhost] =\>  
msg:  
provider:

- net\_id: 3  
net\_ipv4\_subnet: 10.3.0.0/16  
net\_ipv6\_subnet: FD03::/64  
net\_type: dns  
nic\_ids: 

Same result with community.general. **lists\_mergeby** filter:

- name: Combining 2 dictionaries with lists\_mergeby/list\_merge=‘replace’  
vars:  
vpc:  
provider:
- net\_type: ‘db’  
net\_ipv4\_subnet: ‘10.0.0.0/16’  
net\_ipv6\_subnet: ‘FD00::/64’  
net\_id: 0  
nic\_ids:
- 1111111111
- 2222222222
- net\_type: ‘dns’  
net\_ipv4\_subnet: ‘10.1.0.0/16’  
net\_ipv6\_subnet: ‘FD01::/64’  
net\_id: 1  
nic\_ids:
- 3333333333
- 4444444444
- net\_type: ‘ns’  
net\_ipv4\_subnet: ‘10.2.0.0/16’  
net\_ipv6\_subnet: ‘FD02::/64’  
net\_id: 2  
nic\_ids:
- 5555555555
- 6666666666  
seed\_vpc:  
provider:
- net\_type: ‘dns’  
net\_ipv4\_subnet: ‘10.3.0.0/16’  
net\_ipv6\_subnet: ‘FD03::/64’  
net\_id: 3  
nic\_ids:   
new\_vpc: “{{ [vpc.provider, seed\_vpc.provider] | community.general.lists\_mergeby(‘net\_type=dns’, recursive=True, list\_merge=‘replace’) }}”  
debug:  
msg: “{{ new\_vpc }}”

leads to:  
ok: [localhost] =\>  
msg:  
provider:

- net\_id: 3  
net\_ipv4\_subnet: 10.3.0.0/16  
net\_ipv6\_subnet: FD03::/64  
net\_type: dns  
nic\_ids: 

Am I missing something or is it impossible to perform with the currently available ansible filters?

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [August 18, 2023, 4:08pm UTC](https://forum.ansible.com/t/how-to-replace-only-a-specific-entry-in-a-nested-dictionary/38352/2 "2023-08-18T16:08:22Z")

</div>

```auto
---
- name: Replace dict in list example
  hosts: localhost
  gather_facts: false
  vars:
    vpc:
      provider:
        - net_type: 'db'
          net_ipv4_subnet: '10.0.0.0/16'
          net_ipv6_subnet: 'FD00::/64'
          net_id: 0
          nic_ids:
            - 1111111111
            - 2222222222
        - net_type: 'dns'
          net_ipv4_subnet: '10.1.0.0/16'
          net_ipv6_subnet: 'FD01::/64'
          net_id: 1
          nic_ids:
            - 3333333333
            - 4444444444
        - net_type: 'ns'
          net_ipv4_subnet: '10.2.0.0/16'
          net_ipv6_subnet: 'FD02::/64'
          net_id: 2
          nic_ids:
            - 5555555555
            - 6666666666
    fix:
      net_type: 'dns'
      net_ipv4_subnet: '10.3.0.0/16'
      net_ipv6_subnet: 'FD03::/64'
      net_id: 3
      nic_ids: []
  tasks:
    - name: Do this if the order doesn't matter
      # N.B. This assumes there is 1 provider to replace.
      ansible.builtin.debug:
        msg: "{{ item }}"
      loop:
        - "{{ [vpc.provider | selectattr('net_type', 'ne', fix.net_type)] | sum(start=[fix]) }}"

    - name: Do this if the order matters
      # N.B. This will replace _all_ "dns" providers with 'fix'.
      ansible.builtin.debug:
        msg: "{{ item }}"
      loop:
        - |
          {% set providers = [] %}
          {% for p in vpc.provider %}
          {% set _ = providers.append(p if p.net_type != fix.net_type else fix) %}
          {% endfor %}{{ providers }}

```

---

<div class="post-metadata">

**Author:** ![actionmystique](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/actionmystique/32/1678_2.png) [@actionmystique](https://forum.ansible.com/u/actionmystique)\
**Post date:** [August 21, 2023, 3:58pm UTC](https://forum.ansible.com/t/how-to-replace-only-a-specific-entry-in-a-nested-dictionary/38352/3 "2023-08-21T15:58:55Z")

</div>

Very nice 🙂  
As it turns out, there is only one entry of type ‘dns’ , so both solutions work perfectly.
