Score:0

Extract a whole dictionary from a list of dictionaries by value

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.

Score:0
br flag

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 }}`]'
RearAdmiralLieutenantGeneralRi avatar
That worked perfectly, of course! What failed was a rejectattr that I omitted in the original question, that wasn't removing a dict in the list that didn't have the "dict_name" key,
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.