Ansible фильтровать список словарей, чтобы они содержали только уникальные значения в одном поле - PullRequest
2 голосов
/ 01 марта 2020

У меня есть список словарей в переменной ansible. Некоторые словари имеют одно и то же значение в поле 'id и поле 'name', в то время как они отличаются в других парах значений ключа (что для меня не важно). Я хочу отфильтровать все эти словари, которые являются «дубликатами» относительно полей 'name' и 'id'.

Пример:

[{
        "name": "abc",
          "id": "123456",
   "other_key": "unimportant value"
  },
  {
        "name": "abc",
          "id": "123456",
   "other_key": "another unimportant value"
  },
  {
        "name": "bcd",
          "id": "789012",
   "other_key": "unimportant value"
  }]

Желаемый результат:

[{
        "name": "abc",
          "id": "123456"
  },
  {
        "name": "bcd",
          "id": "789012"
  }]

Как мне добиться этого в Ansible? (переменная 'other_key' не обязательно должна быть отброшена, это также может быть, например, только первое вхождение, это просто не имеет значения).

Я уже создал список уникальных идентификаторов с:

{{ mydictionaries | map(attribute='id') | unique | list }}

Но как с этим отфильтровать список словарей?

Ответы [ 2 ]

1 голос
/ 01 марта 2020

Q: "Отфильтровать словари, которые являются" дубликатами "в отношении полей 'name' и 'id'."

A: Данные даны хранится в переменной my_list, давайте добавим в список атрибут hash, созданный из атрибутов name и id. Например,

    - set_fact:
        my_list2: "{{ my_list2|default([]) +
                      [item|combine({'hash': (item.name ~ item.id)|hash})] }}"
      loop: "{{ my_list }}"

    - debug:
        var: my_list2

и

    "my_list2": [
        {
            "hash": "370194ff6e0f93a7432e16cc9badd9427e8b4e13", 
            "id": "123456", 
            "name": "abc", 
            "other_key": "unimportant value"
        }, 
        {
            "hash": "370194ff6e0f93a7432e16cc9badd9427e8b4e13", 
            "id": "123456", 
            "name": "abc", 
            "other_key": "another unimportant value"
        }, 
        {
            "hash": "f3814d5b43a4d67d7636ec64be828d82a92eedbb", 
            "id": "789012", 
            "name": "bcd", 
            "other_key": "unimportant value"
        }
    ]

Следующее использование фильтра groupby и выбор необходимых атрибутов. Например

    - set_fact:
        my_list3: "{{ my_list3|default([]) +
                      [{'name': item.1.0.name, 'id': item.1.0.id}] }}"
      loop: "{{ my_list2|groupby('hash') }}"

    - debug:
        var: my_list3

дай

    "my_list3": [
        {
            "id": "123456", 
            "name": "abc"
        }, 
        {
            "id": "789012", 
            "name": "bcd"
        }
    ]
1 голос
/ 01 марта 2020

Вы можете отфильтровать только нужные ключи из списка карт с помощью json_query, а затем применить фильтр unique.

{{ mydictionnaries | json_query('[].{"name": name, "id": id}') | unique }}

Ниже приведен пример концепции playbook. Обратите внимание, что в приведенном выше коде c требуется, чтобы json_query требовал pip install jmespath на ansible контроллере.

---
- name: Unique filtered dictionaries list example
  hosts: localhost
  gather_facts: false

  vars:
    mydictionaries: [{"name": "abc","id": "123456","other_key": "unimportant value"},{"name": "abc","id": "123456","other_key": "another unimportant value"},{"name": "bcd","id": "789012","other_key": "unimportant value"}]

  tasks:
    - name: Filter out list as wanted
      debug:
        msg: >-
          {{
            mydictionaries
            | json_query('[].{"name": name, "id": id}')
            | unique
          }}

, что дает

PLAY [Unique filtered dictionaries list example] *************************************************************************************************************************************************************************************************************************************

TASK [Filter out list as wanted] ****************************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": [
        {
            "id": "123456",
            "name": "abc"
        },
        {
            "id": "789012",
            "name": "bcd"
        }
    ]
}

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