Home > Software design >  Ansible flatten/merge dict but not fully
Ansible flatten/merge dict but not fully

Time:10-07

I have the following dict

     dict3: [[[{"x": "1","y": "2"},{"z": 3,"h": 4}],{"w": 5}],[[{"x": "333","y": "444"},{"z": "555","h": "777"}],{"w": "999"}]]

I need to make it like this:

    dict": [
                {
                  "x": "1",
                  "y": "2",
                  "z": "3",
                  "h": "4"
                  "w": 5
                }
                {
                  "x": "333",
                  "y": "444"
                  "z": 555,
                  "h": 777
                  "w": 999
                }
            ]

The following command flattens it fully, which I don't want and also does not merge x,y,z,h and w (for each group - there can be many grups).

    - name: "'unnest' all elements into single list"
      ansible.builtin.debug:
        msg: "all in one list {{lookup('community.general.flattened', dict)}}"

This is the result with full flattening (and also not merging):

        "_raw_params": [
            {
                "x": "1",
                "y": "2"
            },
            {
                "h": 4,
                "z": 3
            },
            {
                "w": 5
            },
            {
                "x": "333",
                "y": "444"
            },
            {
                "h": "777",
                "z": "555"
            },
            {
                "w": "999"
            }
        ]

BTW here is the code

   - hosts: localhost
     gather_facts: false
    
     vars:
       dict: [[[{"x": "1","y": "2"},{"z": 3,"h": 4}],{"w": 5}],[[{"x": "333","y": "444"},{"z": "555","h": "777"}],{"w": "999"}]]
    
     tasks:
     - name: UNNEST
       set_fact:
         "{{lookup('community.general.flattened',dict)}}"

Is there a way to do this?

Thanks!

CodePudding user response:

What you want to do is:

  1. flatten individually each element of your top list. You then get a list of lists of dicts
  2. combine individually each element (i.e. the dict lists) from the above result to merge every dicts into a single one.

All of the above is done by applying the corresponding filters to the elements of the top list using the map filter

The following example playbook:

---
- hosts: localhost
  gather_facts: false

  vars:
    dict3: [[[{"x": "1","y": "2"},{"z": 3,"h": 4}],{"w": 5}],[[{"x": "333","y": "444"},{"z": "555","h": "777"}],{"w": "999"}]]

  tasks:
    - debug:
        msg: "{{ dict3 | map('flatten') | map('combine') }}"

Gives:

PLAY [localhost] ***********************************************************************************************************************************************************************************************************************

TASK [debug] ***************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": [
        {
            "h": 4,
            "w": 5,
            "x": "1",
            "y": "2",
            "z": 3
        },
        {
            "h": "777",
            "w": "999",
            "x": "333",
            "y": "444",
            "z": "555"
        }
    ]
}

PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
  • Related