I have two arrays with applications descriptions:
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: ""
And:
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: ""
I need to compare these two arrays based on the version field. So, for example, the desired result should be:
[{
"status": "Active",
"AppName": "Application 3",
"version": "0.3.0",
"metadata": ""
}]
I've tried to use difference filter but it returns also the secondf element - as it has different metadata
- name: Comparing arrays
set_fact:
delta: "{{ source_array | difference(target_array) }}"
And i've got incorrect result:
[{
"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": ""
}]
Any help will be highly appreciated!
This not trivial indeed. You don't provide much context but I suspect what you want to do is something like check if an application has been or should be updated. Right ?
Here is one way:
- 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 }}"
It works by first finding the "newer versions", then screening the original list based on those. But it is a bit brittle cause:
array1
).Maybe you should consider a different data structure, like a mapping (dict). See the current_state
variable below:
- 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
This version fixes the last of the two issues mentioned above. It is also more robust in case the order of the two arrays are not the same, or the array do not have the same length.
The first issue I chose to ignore because, though your question lead to believe array1
and array2
to be interchangeable, I am assuming they are in fact not, within a given context.