Search code examples
ansiblejinja2

Replace value in dictionary by looping through list of dictionaries


I have a dictionary

animals: {
  dogs: [
    "spot",
    "rex"
  ],
  cats: [
    "mittens",
    "felix"
  ]
}

and a list of dictionaries

"details": [
    {
        "pet_id": "5ac76261-7792-46a6-93d9-a8e85da9a51b",
        "pet_name": "spot",
        "owner": "mr. smith"
    },
    {
        "pet_id": "753b1bc9-7309-4e34-8cfd-e68984a25254",
        "pet_name": "mittens",
        "owner": "billy"
    },
    {
        "pet_idwner": "883ee5d7-93c1-4c60-89dc-69001f98173f",
        "pet_name": "rex",
        "owner": "ms. harrison"
    },
    {
        "pet_id": "b1c55e7f-4cc6-4605-b853-7f2e068b87b7",
        "pet_name": "felix",
        "owner": "frank"
    }
]

I'm trying to replace the name in animals with an identifier from details

- ansible.builtin.set_fact:
    replace_name_with_id: |
      {% for k, v in animals.items() %}
      {{k}}: 
      {% for item in v %}
      {% if item in details.pet_name %}
        - {{details[item].pet_id}}
      {% endif %}
      {% endfor %}
      {% endfor %}

What I would like to end up with is

animals: {
  dogs: [
    "5ac76261-7792-46a6-93d9-a8e85da9a51b",
    "883ee5d7-93c1-4c60-89dc-69001f98173f"
  ],
  cats: [
    "753b1bc9-7309-4e34-8cfd-e68984a25254",
    "b1c55e7f-4cc6-4605-b853-7f2e068b87b7"
  ]
}

But what I am getting is

ERROR! failed at splitting arguments, either an unbalanced jinja2 block or quotes


Solution

  • Create the dictionary

      name_id: "{{ details|items2dict(key_name='pet_name', value_name='pet_id') }}"
    

    gives

      name_id:
        felix: b1c55e7f-4cc6-4605-b853-7f2e068b87b7
        mittens: 753b1bc9-7309-4e34-8cfd-e68984a25254
        rex: 883ee5d7-93c1-4c60-89dc-69001f98173f
        spot: 5ac76261-7792-46a6-93d9-a8e85da9a51b
    

    Use it in the template

      animals_id_str: |
        {% for k,v in animals.items() %}
        {{ k }}: {{ v|map('extract', name_id) }}
        {% endfor %}
      animals_id: "{{ animals_id_str|from_yaml }}"
    

    give what you want

      animals_id:
        cats:
        - 753b1bc9-7309-4e34-8cfd-e68984a25254
        - b1c55e7f-4cc6-4605-b853-7f2e068b87b7
        dogs:
        - 5ac76261-7792-46a6-93d9-a8e85da9a51b
        - 883ee5d7-93c1-4c60-89dc-69001f98173f
    

    Example of a complete playbook for testing

    - hosts: localhost
    
      vars:
    
        animals:
          cats: [mittens, felix]
          dogs: [spot, rex]
    
        details:
        - owner: mr. smith
          pet_id: 5ac76261-7792-46a6-93d9-a8e85da9a51b
          pet_name: spot
        - owner: billy
          pet_id: 753b1bc9-7309-4e34-8cfd-e68984a25254
          pet_name: mittens
        - owner: ms. harrison
          pet_id: 883ee5d7-93c1-4c60-89dc-69001f98173f
          pet_name: rex
        - owner: frank
          pet_id: b1c55e7f-4cc6-4605-b853-7f2e068b87b7
          pet_name: felix
    
        name_id: "{{ details|items2dict(key_name='pet_name', value_name='pet_id') }}"
    
        animals_id_str: |
          {% for k,v in animals.items() %}
          {{ k }}: {{ v|map('extract', name_id) }}
          {% endfor %}
        animals_id: "{{ animals_id_str|from_yaml }}"
        
      tasks:
    
        - debug:
            var: name_id
        - debug:
            var: animals_id|to_nice_yaml