【问题标题】:Ansible: compare two arrays by specific fieldAnsible:按特定字段比较两个数组
【发布时间】:2019-05-31 11:17:24
【问题描述】:

我有两个包含应用程序描述的数组:

source_array:
  - status: Active
    AppName": "Application 1"
    version: "0.1.1"
    metadata: ""
  - status": "Active"
    AppName: "Application 2"
    version: "0.2.2"
    metadata: "ID123"
  - status: "Active"
    AppName: "Application 3"
    version: "0.3.3"
    metadata: ""

还有:

target_array:
  - status: "Active"
    AppName: "Application 1"
    version: "0.1.1"
    metadata: ""
  - status: "Active"
    AppName: "Application 2"
    version: "0.2.2"
    metadata: "ID321"
  - status: "Active",
    AppName: "Application 3"
    version: "0.3.0"
    metadata: ""

我需要根据版本字段比较这两个数组。 因此,例如,期望的结果应该是:

[{
    "status": "Active",
    "AppName": "Application 3",
    "version": "0.3.0",
    "metadata": ""
}]

我尝试使用差异过滤器,但它也返回 secondf 元素 - 因为它具有不同的元数据

- name: Comparing arrays
  set_fact:
    delta: "{{ source_array | difference(target_array) }}"

我得到了不正确的结果:

[{
    "status": "Active",
    "AppName": "Application 2",
    "version": "0.2.2",
    "metadata": "ID123"
},
{
    "status": "Active",
    "AppName": "Application 3",
    "version": "0.3.3",
    "metadata": ""
},
{
    "status": "Active",
    "AppName": "Application 2",
    "version": "0.2.2",
    "metadata": "ID321"
},
{
    "status": "Active",
    "AppName": "Application 3",
    "version": "0.3.0",
    "metadata": ""
}]

任何帮助将不胜感激!

【问题讨论】:

标签: ansible list-comparison


【解决方案1】:

这确实不简单。您没有提供太多上下文,但我怀疑您想要做的是检查应用程序是否已经或应该更新。对吧?

这是一种方法:

- hosts: localhost
  vars:
    array1:
      - status: "Active"
        AppName: "Application 1"
        version: "0.1.1"
        metadata: ""
      - status: "Active"
        AppName: "Application 2"
        version: "0.2.2"
        metadata: "ID321"
      - status: "Active"
        AppName: "Application 3"
        version: "0.3.3"
        metadata: ""
    array2:
      - status: "Active"
        AppName: "Application 1"
        version: "0.1.1"
        metadata: ""
      - status: "Active"
        AppName: "Application 2"
        version: "0.2.2"
        metadata: "ID321"
      - status: "Active"
        AppName: "Application 3"
        version: "0.3.0"
        metadata: ""

  tasks:
    - name: "Show matching pattern"
      debug:
        msg: "{{'^' + (array1|map(attribute='version'))|difference(array2|map(attribute='version'))|join('|') + '$'}}"

    - name: "Compare arrays"
      debug:
        msg: "{{ array1 | selectattr('version', 'match', '^' + (array1|map(attribute='version'))|difference(array2|map(attribute='version'))|join('|') + '$') | list }}"

首先找到“较新版本”,然后根据这些筛选原始列表。但它有点脆弱的原因:

  • 它现在假设您,先验哪个数组包含“较新”的数据(这里所有较​​新的版本都在 array1)。
  • 如果您的数组中有两个或多个元素具有相同的版本,它将保留两者,不知道该选择哪个。

也许您应该考虑不同的数据结构,例如映射 (dict)。请参阅下面的 current_state 变量:

- hosts: localhost
  vars:
    current_state:
      "Application 1":
        status: "Active"
        version: "0.1.1"
        metadata: ""
      "Application 2":
        status: "Active"
        version: "0.2.2"
        metadata: "ID321"
      "Application 3":
        status: "Active"
        version: "0.3.0"
        metadata: ""
    new_applications:
      - status: "Active"
        AppName: "Application 1"
        version: "0.1.1"
        metadata: ""
      - status: "Active"
        AppName: "Application 2"
        version: "0.2.2"
        metadata: "ID321"
      - status: "Active"
        AppName: "Application 3"
        version: "0.3.3"
        metadata: ""
      - status: "Active"
        AppName: "Application 4"
        version: "0.1.0"
        metadata: ""
  tasks:
    - name: "Different appraoch"
      debug:
         msg: "{{ item.0 }} -- {{ item.1 }} -- Should update: {{ item.1.version is version((current_state[item.0]|default({'version': '0.0.0'}))['version'], '>') }}"
      loop: "{{ new_applications|map(attribute='AppName')|zip(new_applications)|list }}"

    - name: "Build 'current_state' from a list (if not available as is)"
      # There might be a smarter way using items2dict...
      set_fact:
        dict_from_list: "{{ dict_from_list|default({})|combine({item[0]: item[1]})}}"
      loop: "{{ new_applications|map(attribute='AppName')|zip(new_applications)|list }}"

    - debug:
        var: dict_from_list

此版本修复了上述两个问题中的最后一个。如果两个数组的顺序不同,或者数组的长度不同,它也更加健壮。

我选择忽略的第一个问题是因为尽管您的问题导致人们相信 array1array2 可以互换,但我假设在给定的上下文中它们实际上不是。

【讨论】:

  • 完美!基本上,这两个问题都是我需要实现的。这个剧本是将包从一个环境部署到另一个环境 - 从 DEV 到 TESTING,所以第一个阵列总是有更新的版本 - 无论更高或更低。如果它将使两个项目具有相同的版本 - 也是完美的,因为在现实世界中我在项目中还有一些其他选项 - 并且我可能会有多个具有相同版本但选项不同的应用程序。非常感谢您的解决方案!
  • @user41995 那么,你会考虑接受这个答案吗?谢谢。
猜你喜欢
  • 2019-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-29
  • 1970-01-01
  • 2018-12-03
  • 2022-01-22
相关资源
最近更新 更多