Ansible:按特定字段比较两个数组
Ansible: compare two arrays by specific field
我有两个包含应用程序描述的数组:
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": ""
}]
我尝试使用差异过滤器,但它 returns 也是 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": ""
}]
非常感谢任何帮助!
这确实不简单。您没有提供太多上下文,但我怀疑您想要做的是检查应用程序是否已经更新或应该更新。对吗?
这是一种方法:
- 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 }}"
它的工作原理是首先找到 "newer versions",然后根据这些筛选原始列表。但它有点脆弱原因:
- 它现在假设你先验哪个数组包含"newer"数据(这里所有较新的版本都在
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
此版本修复了上述两个问题中的最后一个。如果两个数组的顺序不同,或者数组的长度不同,它也更健壮。
我选择忽略的第一个问题是因为,虽然你的问题导致人们相信 array1
和 array2
可以互换,但我假设在给定的上下文中它们实际上不是。
我有两个包含应用程序描述的数组:
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": ""
}]
我尝试使用差异过滤器,但它 returns 也是 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": ""
}]
非常感谢任何帮助!
这确实不简单。您没有提供太多上下文,但我怀疑您想要做的是检查应用程序是否已经更新或应该更新。对吗?
这是一种方法:
- 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 }}"
它的工作原理是首先找到 "newer versions",然后根据这些筛选原始列表。但它有点脆弱原因:
- 它现在假设你先验哪个数组包含"newer"数据(这里所有较新的版本都在
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
此版本修复了上述两个问题中的最后一个。如果两个数组的顺序不同,或者数组的长度不同,它也更健壮。
我选择忽略的第一个问题是因为,虽然你的问题导致人们相信 array1
和 array2
可以互换,但我假设在给定的上下文中它们实际上不是。