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

如何用jq将对象列表转换为嵌套单对象(Ansible场景)

问题:Ansible中高效转换大型JSON为嵌套字典

在Ansible处理大型JSON响应时,因原结构导致搜索速度慢,需要将字典列表转换为单个嵌套字典。Ansible自带的jmespath无法实现值转键,尝试了支持jq的社区插件,但只能硬编码顶层字典。

示例输入JSON

{
  "json": {
    "@code": "19",
    "@status": "success",
    "result": {
      "@count": "7003",
      "@total-count": "7003",
      "entry": [
        {
          "@location": "shared",
          "@name": "bgp_routers",
          "static": {
            "member": [
              "core-1",
              "core-2",
              "core-3",
              "supercore"
            ]
          }
        },
        {
          "@location": "shared",
          "@name": "web_servers",
          "description": "req-5",
          "static": {
            "member": [
              "web001",
              "web002",
              "web004"
            ]
          }
        },
        {
          "@location": "remote-site-1",
          "@name": "web_servers-2",
          "description": "req-100",
          "static": {
            "member": [
              "web001",
              "web003",
              "web004"
            ]
          }
        }
      ]
    }
  }
}

期望转换后的嵌套结构

{
    "shared": {
      "bgp_routers": {
        "@location": "shared",
        "@name": "bgp_routers",
        "static": {
          "member": [
            "core-1",
            "core-2",
            "core-3",
            "supercore"
          ]
        }
      },
      "web_servers": {
        "@location": "shared",
        "@name": "web_servers",
        "description": "req-5",
        "static": {
          "member": [
            "web001",
            "web002",
            "web004"
          ]
        }
      }
    },
    "remote-site-1": {
      "web_servers-2": {
        "@location": "remote-site-1",
        "@name": "web_servers-2",
        "description": "req-100",
        "static": {
          "member": [
            "web001",
            "web003",
            "web004"
          ]
        }
      }
    }
}

当前尝试的问题

使用以下jq语句:

.json.result.entry | map({ (.["@location"]):  {( .["@name"] ): . }})

得到的结果无法合并相同的shared键,使用add只会保留最后一个shared条目:

[
  {
    "shared": {
      "bgp_routers": {
        "@location": "shared",
        "@name": "bgp_routers",
        "static": {
          "member": [
            "core-1",
            "core-2",
            "core-3",
            "supercore"
          ]
        }
      }
    }
  },
  {
    "shared": {
      "web_servers": {
        "@location": "shared",
        "@name": "web_servers",
        "description": "req-5",
        "static": {
          "member": [
            "web001",
            "web002",
            "web004"
          ]
        }
      }
    }
  },
  {
    "remote-site-1": {
      "web_servers-2": {
        "@location": "remote-site-1",
        "@name": "web_servers-2",
        "description": "req-100",
        "static": {
          "member": [
            "web001",
            "web003",
            "web004"
          ]
        }
      }
    }
  }
]

另外,不使用Ansible的|combine过滤器是因为处理大循环时性能极低,每次迭代都会删除并重建字典。


解决方案:使用jq的reduce和递归合并操作符

要实现相同@location下的条目合并,需用jq的reduce遍历条目,结合递归合并操作符*来合并同位置的字典,替代简单的add。

最终jq语句

.json.result.entry | reduce .[] as $item ({}; . * { ($item["@location"]): { ($item["@name"]): $item } })

逻辑解释

  • reduce .[] as $item ({}; ...):以空字典为初始值,遍历每个条目$item
  • . * { ... }:使用*操作符递归合并当前结果和新生成的条目字典,相同@location下的子字典会被合并而非覆盖
  • { ($item["@location"]): { ($item["@name"]): $item } }:为每个条目生成对应嵌套结构,和之前的map逻辑一致,但通过reduce+*实现合并

效果验证

执行上述语句后,会直接输出期望的嵌套结构,且处理大型数据集时性能远优于Ansible的combine循环,因为jq的合并操作是原生高效实现的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 01:51:07