You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用jq保留父键层级切片嵌套JSON对象?

解决jq路径过滤器保留完整父层级的问题

嘿,我明白你想要的效果——不用两次调用jq,直接通过一次jq处理,从指定的路径过滤器反向构建出包含所有父层级的JSON结构对吧?其实用jq本身的getpath和reduce就能轻松实现,而且完全适配任意合法的JSON对象和路径过滤器。

核心思路

我们需要把路径过滤器(比如.a.b.c)拆解成键数组,获取目标路径对应的值,然后从叶子节点往根节点逐层嵌套,最终得到包含完整父层级的JSON结构。

实现方案

单jq命令实现

直接用以下命令就能完成需求,把Bash变量F(路径过滤器)和O(JSON对象)传入即可:

jq --arg filter "$F" '
  # 把路径过滤器转换为键数组(去掉开头的.,再按.分割)
  ($filter | sub("^\\."; "") | split(".")) as $keys
  # 获取目标路径对应的值
  | getpath($keys) as $value
  # 反向遍历键数组,逐层构建嵌套对象
  | reduce ($keys | reverse[]) as $key (
      $value;
      { ($key): . }
    )
' <<< "$O"

测试示例

用你给出的例子测试:

O=' { "a": { "b": { "c": { "p":1 }, "x": 1 }, "x": 2 }, "x": 3 }'
F='.a.b.c'

执行上面的命令后,输出结果正好是你期望的:

{
  "a": {
    "b": {
      "c": {
        "p": 1
      }
    }
  }
}

代码解释

  • --arg filter "$F":将Bash中的路径过滤器变量F传递给jq,命名为$filter。
  • $filter | sub("^\\."; "") | split("."):处理路径字符串,去掉开头的.,再按.分割成键数组(比如.a.b.c会变成["a","b","c"])。
  • getpath($keys):通过键数组获取JSON对象中对应路径的值(这里就是{"p":1})。
  • reduce ($keys | reverse[]) as $key ($value; { ($key): . }):反向遍历键数组(从c到b再到a),每次把当前结果包裹到以当前键为名称的对象中,最终构建出完整的父层级结构。

边界情况适配

  • 如果路径过滤器是根节点(F="."):此时键数组为空,reduce不会执行,直接返回整个JSON对象,符合预期。
  • 如果路径不存在(比如F=".a.b.d"):getpath会返回null,最终结果会生成包含该路径的结构,对应值为null,逻辑合理。

封装成Bash函数(可选)

如果需要频繁使用,可以封装成一个Bash函数:

jq_nested_filter() {
  local filter="$1"
  local json="$2"
  jq --arg filter "$filter" '
    ($filter | sub("^\\."; "") | split(".")) as $keys
    | getpath($keys) as $value
    | reduce ($keys | reverse[]) as $key (
        $value;
        { ($key): . }
      )
  ' <<< "$json"
}

调用方式:

jq_nested_filter ".a.b.c" "$O"

内容的提问来源于stack exchange,提问作者Steve Amerige

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:14:47