【问题标题】:Passing nested json argument variable as key to JQ json library将嵌套的 json 参数变量作为键传递给 JQ json 库
【发布时间】:2021-12-11 18:40:41
【问题描述】:

我有两个 JSON 文件要传递给 jq 对象,请检查以下内容:

创建.json

{
    "email_notifications": {
        "on_failure": "_"
    },
    "name": "_",
    "schedule": {
        "quartz_cron_expression": "_",
        "timezone_id": "Europe/Amsterdam",
        "pause_status": "_"
    }
}

更新.json

{
    "job_id": "_",
    "new_settings": {
        "email_notifications": {
            "on_failure": "_"
        },
        "name": "_",
        "schedule": {
            "quartz_cron_expression": "_",
            "timezone_id": "Europe/Amsterdam",
            "pause_status": "_"
        }
}

对于 Create.json,我可以使用以下表达式:

TEMPLATE=`cat $FILE | jq
--arg _parent "$PARENT"
--arg _job_name "$JOB_NAME"
' ( . | .name ) |= $_job_name
| ( . | .schedule.pause_status) |= $_parent'
`

对于 Update.json,我需要使用表达式来包含父键名:

TEMPLATE=`cat $FILE | jq
    --arg _parent "$PARENT"
    --arg _job_name "$JOB_NAME"
    ' ( .["new_settings"] | .name ) |= $_job_name
    | ( .["new_settings"] | .schedule.pause_status) |= $_parent'

为了处理这个问题,我在表达式中使用了 if else 并且效果很好: ( if .job_id? then .["new_settings"] else . end | .name ) |= $_job_name

但我想将初始部分作为参数传递,但它不起作用并给出语法错误。如何使参数在传递时成为运行时表达式的动态:

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'

【问题讨论】:

  • 为什么都是stuff | .stuff?只是.[$filter].name |= $_job_name,不是吗?
  • 这两个文件如何工作? Update.json 有“new_settings”,但 Create.json 没有这个。那么 .[$filter] 在这里如何证明是合理的呢?
  • 您不能将(另一个)jq 过滤器作为参数传递,但您可以使用 shell 变量构造(一个)过滤器。您可以使用参数--argjson 而不是--arg 传递json 内容。
  • --arg filter 1_or_0 'if $filter == "0" . else .["new_settings"] end | .. 怎么样?你总是可以做' ( '"$Filter"' ...
  • 我不想使用 if else,我已经实现了这种方法,我希望我的论点在运行时取代 .或 .["new_settings"]

标签: shell arguments expression jq


【解决方案1】:
# --arg root_path ""
# --arg root_path "new_settings"

getpath( $root_path | split(".") ) |= (
   .name                  = $_job_name |
   .schedule.pause_status = $_parent
)

参数不应该是一段 jq 代码。接受一段 jq 代码传递给eval 是一种不好的做法。但是jq 甚至没有eval,所以它甚至不是一个选项。

我们可以使用 JSON 数组提供路径。

# --argjson root_path '[]'
# --argjson root_path '["new_settings"]'

getpath($root_path)

但是点分隔的路径要好得多。

# --arg root_path ""
# --arg root_path "new_settings"

getpath( $root_path | split(".") )                           # Supports objects
getpath( $root_path | split(".") | map( tonumber? // . ) )   # Supports objects & arrays

这给了我们这样的东西:

getpath( $root_path | split(".") ) as $root |
( $root | .name                  ) |= $_job_name |
( $root | .schedule.pause_status ) |= $_parent

除非使用两次$root 没有意义。

getpath( $root_path | split(".") ) as $root |
$root |= (
   .name                  |= $_job_name |
   .schedule.pause_status |= $_parent
)

或者只是

getpath( $root_path | split(".") ) |= (
   .name                  |= $_job_name |
   .schedule.pause_status |= $_parent
)

=|= 之间的唯一区别是右侧提供的上下文 (.)。因此可以将先前存在的两个|= 简化为=

getpath( $root_path | split(".") ) |= (
   .name                  = $_job_name |
   .schedule.pause_status = $_parent
)

Demo on jqplayCreate.json
Demo on jqplayUpdate.json

【讨论】:

  • 有什么区别? = 和 |=
  • @shzyincu 我对它进行了适当的问答here
  • ikegami 谢谢,成功了。
  • 使用数组时下面不起作用:jqplay.org/s/Uy1VSpzkkx
  • @shzyincu, This part 看起来不对。它可能缺少括号。评论不是发布新问题的地方
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-04-26
  • 2019-03-14
  • 2021-06-30
  • 2019-12-26
  • 2017-04-04
  • 2021-03-22
  • 2021-07-04
相关资源
最近更新 更多