Issue
I have two JSON files that I am passing to the jq object, check below:
Create.json
{
"email_notifications": {
"on_failure": "_"
},
"name": "_",
"schedule": {
"quartz_cron_expression": "_",
"timezone_id": "Europe/Amsterdam",
"pause_status": "_"
}
}
Update.json
{
"job_id": "_",
"new_settings": {
"email_notifications": {
"on_failure": "_"
},
"name": "_",
"schedule": {
"quartz_cron_expression": "_",
"timezone_id": "Europe/Amsterdam",
"pause_status": "_"
}
}
for Create.json i can use below expression:
TEMPLATE=`cat $FILE | jq
--arg _parent "$PARENT"
--arg _job_name "$JOB_NAME"
' ( . | .name ) |= $_job_name
| ( . | .schedule.pause_status) |= $_parent'
`
for Update.json I need to use the expression to include the parent key name:
TEMPLATE=`cat $FILE | jq
--arg _parent "$PARENT"
--arg _job_name "$JOB_NAME"
' ( .["new_settings"] | .name ) |= $_job_name
| ( .["new_settings"] | .schedule.pause_status) |= $_parent'
To handle this I have used if else in the expression and it works perfectly: ( if .job_id? then .["new_settings"] else . end | .name ) |= $_job_name
but I want to pass the initial part as an argument, but it doesn't work and gives a syntax error. How can i make it dynamic that an argument becomes an expression on runtime when passed:
Filter="." OR Filter=".["new_settings"]"
TEMPLATE=`cat $FILE | jq
--arg filter "$Filter"
--arg _parent "$PARENT"
--arg _job_name "$JOB_NAME"
' ( $filter | .name ) |= $_job_name
| ( $filter | .schedule.pause_status) |= $_parent'
Solution
# --arg root_path ""
# --arg root_path "new_settings"
getpath( $root_path | split(".") ) |= (
.name = $_job_name |
.schedule.pause_status = $_parent
)
The argument shouldn't be a piece of jq code. It would be a bad practice to accept a piece of jq code to pass to eval
. But jq
doesn't even have eval
, so it's not even an option.
We could provide a path using a JSON array.
# --argjson root_path '[]'
# --argjson root_path '["new_settings"]'
getpath($root_path)
But a dot-separated path is much nicer.
# --arg root_path ""
# --arg root_path "new_settings"
getpath( $root_path | split(".") ) # Supports objects
getpath( $root_path | split(".") | map( tonumber? // . ) ) # Supports objects & arrays
This gives us something like this:
getpath( $root_path | split(".") ) as $root |
( $root | .name ) |= $_job_name |
( $root | .schedule.pause_status ) |= $_parent
Except there's no point in using $root
twice.
getpath( $root_path | split(".") ) as $root |
$root |= (
.name |= $_job_name |
.schedule.pause_status |= $_parent
)
or just
getpath( $root_path | split(".") ) |= (
.name |= $_job_name |
.schedule.pause_status |= $_parent
)
The only difference between =
and |=
is the context (.
) provided to the right-hand side. The two previously-existing |=
can therefore be simplified to =
.
getpath( $root_path | split(".") ) |= (
.name = $_job_name |
.schedule.pause_status = $_parent
)
Demo on jqplay Create.json
Demo on jqplay Update.json
Answered By - ikegami