I have a json like this
[{"version": 0.0,"Resources": [ {"TargetService": {"Type": "AWS::ECS::Service","Properties": {"TaskDefinition": "abc","LoadBalancerInfo": {"ContainerName": "def","ContainerPort": 8080}}}} ]}]
My attempt is to replace TaskDefinition key value from "abc" to "123" and ContainerName key value from "def" to "456 in one command and return the whole update json.
This is what i tried
echo $APP_SPEC | jq --arg TASK_DEFINITION "123" '(.[].Resources[].TargetService | select(.Properties)).TaskDefinition |=$TASK_DEFINITION')
But the substistuion is not happening properly and the value gets appended at the end of the josn as below.
Incorrect response:
[ { "version": 0, "Resources": [ { "TargetService": { "Type": "AWS::ECS::Service", "Properties": { "TaskDefinition": "abc", "LoadBalancerInfo": { "ContainerName": "container_name", "ContainerPort": 8080 } }, "TaskDefinition": "123" } } ] } ]
3
Answers
Both the above solutions works perfectly fine. Thanks @Knittl and @pmf. For others who are stuck with this kind of problem here is my complete command to pass two variables to jq and replace the values in one shot.
Use the update operator
|=
Demo
Note that
select
only filters its input, it does not descend into the filter criterion. So, if you only want to make the update if the.Properties
field exists, useselect
and descend into it.Demo
Note that the filter
select(.Properties)
will producefalse
if the content of that field, albeit existing, evaluates tonull
orfalse
. If you want to consider such cases also as "existent", usehas
in theselect
filter to test for it.Demo
You don’t need
select
, you can specify the path directly:Or group by the top level property:
It’s also possible to recursively merge the expected object into your existing object using
*=
:Output of all three variants: