I want to merge the .environments.default and .environments.dev objects together, so that dev values override any default values and default values fill in anything not defined in the dev object. If I use .environments.default * .environments.dev most of the objects are merged correctly, except for the array lists under the env and secrets objects. The entire dev object is used, but I want the array lists to be merged with unique values.
Is there anyway to get this result with jq? If it helps I could also try doing this in yq with the YAML file.
I would also really like to know if this is possible without hardcoding "env" or "secrets" anywhere in the code.
When I use .environments.default * .environments.dev on the below source...
Source:
{
"environments": {
"default": {
"config": {
"security": {
"user": 0,
"group": 0
},
"resources": {
"limits": {
"memory": "256Mi",
"cpu": "500m"
}
},
"env": [
{
"name": "DEFAULT_ENV",
"value": "DEFAULT_ENV_VALUE"
},
{
"name": "BASE_URL",
"value": "DEFAULT_BASE_URL"
}
],
"secrets": [
{
"secretID": "567",
"mountPath": "/default/dir/to/567/path"
},
{
"secretID": "123",
"mountPath": "/default/dir/to/123/path"
},
{
"secretUUID": "789",
"mountPath": "/default/dir/to/789/path"
}
]
}
},
"dev": {
"config": {
"replicas": 1,
"resources": {
"limits": {
"cpu": "5000m"
}
},
"env": [
{
"name": "BASE_URL",
"value": "DEV_BASE_URL"
},
{
"name": "DEV_ENV_1",
"value": "DEV_ENV_1"
}
],
"secrets": [
{
"secretID": "456",
"mountPath": "/dev/dir/to/456/path"
},
{
"secretID": "123",
"mountPath": "/dev/dir/to/456/path"
}
]
}
}
}
}
I get...
Current output:
{
"config": {
"security": {
"user": 0,
"group": 0
},
"resources": {
"limits": {
"memory": "256Mi",
"cpu": "5000m"
}
},
"env": [
{
"name": "BASE_URL",
"value": "DEV_BASE_URL"
},
{
"name": "DEV_ENV_1",
"value": "DEV_ENV_1"
}
],
"secrets": [
{
"secretID": "456",
"mountPath": "/dev/dir/to/456/path"
},
{
"secretID": "123",
"mountPath": "/dev/dir/to/456/path"
}
],
"replicas": 1
}
}
but I want...
Desired output:
{
"config": {
"security": {
"user": 0,
"group": 0
},
"resources": {
"limits": {
"memory": "256Mi",
"cpu": "5000m"
}
},
"env": [
{
"name": "BASE_URL",
"value": "DEV_BASE_URL"
},
{
"name": "DEV_ENV_1",
"value": "DEV_ENV_1"
},
{
"name": "DEFAULT_ENV",
"value": "DEFAULT_ENV_VALUE"
}
],
"secrets": [
{
"secretID": "456",
"mountPath": "/dev/dir/to/456/path"
},
{
"secretID": "123",
"mountPath": "/dev/dir/to/456/path"
},
{
"secretID": "567",
"mountPath": "/default/dir/to/567/path"
},
{
"secretUUID": "789",
"mountPath": "/default/dir/to/789/path"
}
],
"replicas": 1
}
}
From the comments thread:
So, let the fun begin:
This captures and iterates over all items of non-empty arrays from the
.defaultbranch (saving the array path withpaths(arrays | select(has(0))), each item's value withgetpath(…)[], and the first item's key and value usingto_entries[0]). The iteration's base document is the merge you already performed, but with these arrays removed from the.defaultbranch, so the saved items can be individually tested and appended to it if they pass the condition that no other first key's value matches theirs:IN(.[][$v0.key]; $v0.value) | not.Demo