'Merge two nested JSON files using JQ
I'm trying to merge two JSON files. The main destination is to overwrite environment variables in the 1st file with environment variables in the 2nd.
1st file:
{
"containerDefinitions": [
{
"name": "foo",
"image": "nginx:latest",
"cpu": 1024,
"memory": 4096,
"memoryReservation": 2048,
"portMappings": [
{
"containerPort": 8080,
"hostPort": 0,
"protocol": "tcp"
}
],
"essential": true,
"environment": [
{
"name": "SERVER_PORT",
"value": "8080"
},
{
"name": "DB_NAME",
"value": "example_db"
}
],
"mountPoints": [],
"volumesFrom": [],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/dev/ecs/example",
"awslogs-region": "us-west-1",
"awslogs-stream-prefix": "ecs"
}
}
}
],
"family": "bar",
"taskRoleArn": "arn:aws:iam::111111111111:role/assume-ecs-role",
"executionRoleArn": "arn:aws:iam::111111111111:role/ecs-task-execution-role",
"networkMode": "bridge",
"volumes": [],
"placementConstraints": [],
"requiresCompatibilities": [
"EC2"
]
}
2nd file:
{
"containerDefinitions": [
{
"environment": [
{
"name": "SERVER_PORT",
"value": "8081"
}
]
}
]
}
The product has to be next:
{
"containerDefinitions": [
{
"name": "foo",
"image": "nginx:latest",
"cpu": 1024,
"memory": 4096,
"memoryReservation": 2048,
"portMappings": [
{
"containerPort": 8080,
"hostPort": 0,
"protocol": "tcp"
}
],
"essential": true,
"environment": [
{
"name": "SERVER_PORT",
"value": "8081"
},
{
"name": "DB_NAME",
"value": "example_db"
}
],
"mountPoints": [],
"volumesFrom": [],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/dev/ecs/example",
"awslogs-region": "us-west-1",
"awslogs-stream-prefix": "ecs"
}
}
}
],
"family": "bar",
"taskRoleArn": "arn:aws:iam::111111111111:role/assume-ecs-role",
"executionRoleArn": "arn:aws:iam::111111111111:role/ecs-task-execution-role",
"networkMode": "bridge",
"volumes": [],
"placementConstraints": [],
"requiresCompatibilities": [
"EC2"
]
}
I tried to do next:
jq -s 'reduce .[] as $item ({}; reduce ($item | keys_unsorted[]) as $key (.; $item[$key] as $val | ($val | type) as $type | .[$key] = if ($type == "array") then (.[$key] + $val | unique) elif ($type == "object") then (.[$key] + $val) else $val end))' 1.json 2.json
But the result is:
{
"containerDefinitions": [
{
"name": "foo",
"image": "nginx:latest",
"cpu": 1024,
"memory": 4096,
"memoryReservation": 2048,
"portMappings": [
{
"containerPort": 8080,
"hostPort": 0,
"protocol": "tcp"
}
],
"essential": true,
"environment": [
{
"name": "SERVER_PORT",
"value": "8080"
},
{
"name": "DB_NAME",
"value": "example_db"
}
],
"mountPoints": [],
"volumesFrom": [],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/dev/ecs/example",
"awslogs-region": "us-west-1",
"awslogs-stream-prefix": "ecs"
}
}
},
{
"environment": [
{
"name": "SERVER_PORT",
"value": "8081"
}
]
}
],
"family": "bar",
"taskRoleArn": "arn:aws:iam::111111111111:role/assume-ecs-role",
"executionRoleArn": "arn:aws:iam::111111111111:role/ecs-task-execution-role",
"networkMode": "bridge",
"volumes": [],
"placementConstraints": [],
"requiresCompatibilities": [
"EC2"
]
}
Could anyone help to find out how to reach the right result?
Solution 1:[1]
Something like this will do the trick:
(input | .containerDefinitions[0].environment | from_entries) as $new_env
| input | .containerDefinitions[].environment |= ((from_entries + $new_env) | to_entries)
In case it's unclear, the invocation should look like so:
jq -n '...' 2.json 1.json
Solution 2:[2]
Here's a solution using tostream and has(1) to read the values from the second file, and setpath to set them in the first file:
jq 'reduce (input | tostream | select(has(1))) as $i (.; setpath($i[0]; $i[1]))' \
1.json 2.json
When providing the files in reversed order (2.json 1.json), the context . and input have to be swapped:
jq 'reduce (tostream | select(has(1))) as $i (input; setpath($i[0]; $i[1]))' \
2.json 1.json
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | oguz ismail |
| Solution 2 | pmf |
