0

I need to extract a whole dictionary from a list of dictionaries based on a value.

"msg": [
    {
        "duplicate_key": "in dict_name_one",
        "KEY_1_dict_name_one": "VALUE_1_dict_name_one",
        "KEY_2_could_be anything": "VALUE_2_dict_name_one",
        "dict_name": "dict_name_one"
    },
    {
        "duplicate_key": "in dict_name_two",
        "KEY_1_second_dict": "VALUE_1_second_dict",
        "KEY_2_d_two": "VALUE_2_could_be anything",
        "dict_name": "dict_name_two"
    }
]

I would like to match on the Value of "dict_name" (when dict_name == dict_name_two)and get only dictionary containing that match back.

{
    "duplicate_key": "in dict_name_two",
    "KEY_1_second_dict": "VALUE_1_second_dict",
    "KEY_2_d_two": "VALUE_2_could_be anything",
    "dict_name": "dict_name_two"
}

The only constant is here is the Key "dict_name".

I already have a loop and a rejectattr on dict_name to set a bunch of facts off the remaining key/values pairs.

1 Answers1

0

Given the list

  l0:
    - KEY_1_dict_name_one: VALUE_1_dict_name_one
      KEY_2_could_be anything: VALUE_2_dict_name_one
      dict_name: dict_name_one
      duplicate_key: in dict_name_one
    - KEY_1_second_dict: VALUE_1_second_dict
      KEY_2_d_two: VALUE_2_could_be anything
      dict_name: dict_name_two
      duplicate_key: in dict_name_two
    - KEY_1_second_dict: VALUE_1_second_dict
      KEY_2_d_two: VALUE_2_could_be anything
      duplicate_key: in dict_name_two

remove the items where the attribute dict_name is missing

  l1: "{{ l0|rejectattr('dict_name', 'undefined') }}"

gives

  l1:
    - KEY_1_dict_name_one: VALUE_1_dict_name_one
      KEY_2_could_be anything: VALUE_2_dict_name_one
      dict_name: dict_name_one
      duplicate_key: in dict_name_one
    - KEY_1_second_dict: VALUE_1_second_dict
      KEY_2_d_two: VALUE_2_could_be anything
      dict_name: dict_name_two
      duplicate_key: in dict_name_two

There are more options. If the values of the attribute dict_name are unique create the dictionary

  d1: "{{ dict(l1|map(attribute='dict_name')|zip(l1)) }}"

gives

  d1:
    dict_name_one:
      KEY_1_dict_name_one: VALUE_1_dict_name_one
      KEY_2_could_be anything: VALUE_2_dict_name_one
      dict_name: dict_name_one
      duplicate_key: in dict_name_one
    dict_name_two:
      KEY_1_second_dict: VALUE_1_second_dict
      KEY_2_d_two: VALUE_2_could_be anything
      dict_name: dict_name_two
      duplicate_key: in dict_name_two

The search is trivial now.


Example of a complete playbook for testing

- hosts: localhost

  vars:

    l1:
      - KEY_1_dict_name_one: VALUE_1_dict_name_one
        KEY_2_could_be anything: VALUE_2_dict_name_one
        dict_name: dict_name_one
        duplicate_key: in dict_name_one
      - KEY_1_second_dict: VALUE_1_second_dict
        KEY_2_d_two: VALUE_2_could_be anything
        dict_name: dict_name_two
        duplicate_key: in dict_name_two

    d1: "{{ dict(l1|map(attribute='dict_name')|zip(l1)) }}"

  tasks:

    - debug:
        var: l1
    - debug:
        var: d1

The next option is either the filter selectattr or json_query

    - debug:
        msg: "{{ l1|selectattr('dict_name', 'eq', 'dict_name_two') }}"

    - debug:
        msg: "{{ l1|json_query('[?dict_name == `dict_name_two`]') }}"

Both options provide a list of the selected dictionaries because there might more items with the same value of the attribute dict_name

  msg:
  - KEY_1_second_dict: VALUE_1_second_dict
    KEY_2_d_two: VALUE_2_could_be anything
    dict_name: dict_name_two
    duplicate_key: in dict_name_two

If you want to substitute a variable the expressions below give the same results

    - debug:
        msg: "{{ l1|selectattr('dict_name', 'eq', dict_name) }}"
      vars:
        dict_name: dict_name_two

    - debug:
        msg: "{{ l1|json_query(_query) }}"
      vars:
        dict_name: dict_name_two
        _query: '[?dict_name == `{{ dict_name }}`]'

Example of a complete playbook for testing

 hosts: localhost

  vars:

    l1:
      - KEY_1_dict_name_one: VALUE_1_dict_name_one
        KEY_2_could_be anything: VALUE_2_dict_name_one
        dict_name: dict_name_one
        duplicate_key: in dict_name_one
      - KEY_1_second_dict: VALUE_1_second_dict
        KEY_2_d_two: VALUE_2_could_be anything
        dict_name: dict_name_two
        duplicate_key: in dict_name_two

  tasks:

    - debug:
        msg: "{{ l1|selectattr('dict_name', 'eq', 'dict_name_two') }}"
    - debug:
        msg: "{{ l1|json_query('[?dict_name == `dict_name_two`]') }}"

    - debug:
        msg: "{{ l1|selectattr('dict_name', 'eq', dict_name) }}"
      vars:
        dict_name: dict_name_two
    - debug:
        msg: "{{ l1|json_query(_query) }}"
      vars:
        dict_name: dict_name_two
        _query: '[?dict_name == `{{ dict_name }}`]'
Vladimir Botka
  • 5,138
  • 8
  • 20