gpt4 book ai didi

json - jq 1.5 - 更改现有元素或添加新元素(如果不存在)

转载 作者:行者123 更新时间:2023-12-05 06:36:32 26 4
gpt4 key购买 nike

使用:

目标和条件:

  1. 用另一个值替换一个子对象值,在任何深度,具有父对象或数组,例如:
    • 如果 .spec.template.spec.containers[n].env[n].name == "CHANGEME"那么
    • .spec.template.spec.containers[n].env[n].value = "xx"
    • 其中 n>=0
  2. 如果 .name 的任何父级不存在,应该能够即时添加它们而不是因错误而退出
  3. 输出 JSON 应至少具有与输入 JSON 相同的元素,不应丢失现有元素
  4. 数组元素中不允许重复,但顺序必须保留,因此函数类似于unique不能使用

示例输入 JSON:

结构其实是强加的,我只好服从。对象“路径”通常类似于:.spec.template.spec.containers[0].spec.env[1].name .您还可以有 .containers[1],等等。这是高度可变的,有时某些元素可能存在或不存在,取决于特定 JSON 的模式定义。

[
{
"kind": "StatefulSet",
"spec": {
"serviceName": "cassandra",
"template": {
"spec": {
"containers": [
{
"name": "cassandra",
"env": [
{
"name": "CASSANDRA_SEEDS",
"value": "cassandra-0.cassandra.kong.svc.cluster.local"
},
{
"name": "CHANGEME",
"value": "K8"
}
]
}
]
}
}
}
}
]

场景

  1. 在保留输入结构的同时替换现有值,按预期工作:
    • jq -r 'map({name:"CHANGEME",value: "xx"} as $v | (.spec.template.spec.containers[].env[] | select(.name==$v.name))|=$v)'
  2. 假设我想做同样的事情,只是 .env1 是对象 {name:"",value:""} 的父数组。预期的输出应该是:

    [
    {
    "kind": "StatefulSet",
    "spec": {
    "serviceName": "cassandra",
    "template": {
    "spec": {
    "containers": [
    {
    "name": "cassandra",
    "env": [
    {
    "name": "CASSANDRA_SEEDS",
    "value": "cassandra-0.cassandra.kong.svc.cluster.local"
    },
    {
    "name": "CHANGEME",
    "value": "K8"
    }
    ],
    "env1": [
    {
    "name": "CHANGEME",
    "value": "xx"
    }
    ]
    }
    ]
    }
    }
    }
    }
    ]
    • 为此,我尝试动态添加对象 env1:
      • jq -r 'map({name:"CHANGEME",value: "xx"} as $v | (.spec.template.spec.containers[] | if .env1 == null then .+={env1:[$v]} | .env1 else .env1 end | .[] | select(.name==$v.name))|=$v)'
        • 如果 .env1 存在则有效,否则:
        • 错误:试图访问 {"name":"cassandra","env".. 的元素 "env1"附近的无效路径表达式。
        • 如果使用类似 .env//[$v] 的符号,结果相同或 .env//=.env[$v]
      • jq -r 'map({name:"CHANGEME",value: "xx"} as $v | (.spec.template.spec.containers[].env1 | .[if length<0 then 0 else length end]) |= $v)'
        • 如果 .env1 存在则有效
        • 如果数组 .env1 存在则添加另一个元素,可能会重复对象
    • 最终我成功地创建了一个有效的过滤器:
      • jq -r 'def defarr: if length<=0 then .[0] else .[] end; def defarr(item): if length<=0 then .[0] else foreach .[] as $item ([]; if $item.name == item then $item else empty end; .) end; map({name:"CHANGEME",value: "xx"} as $v | (.spec.template.spec | .containers1 | defarr | .env1 | defarr($v.name) ) |=$v)'
        • 这按预期工作,但是太长太重,必须在对象层次结构中的每个潜在数组之后添加自定义函数

问题

有什么方法可以简化这一切,让它更通用一点来处理任意数量的父级,数组与否?

谢谢。

最佳答案

“问题”

在回答问题时:是的。 jq 1.5 有 keys_unsorted,所以你可以使用下面的 walk/1 定义,它现在是 jq 的“master”版本的标准:

# Apply f to composite entities recursively, and to atoms
def walk(f):
. as $in
| if type == "object" then
reduce keys_unsorted[] as $key
( {}; . + { ($key): ($in[$key] | walk(f)) } ) | f
elif type == "array" then map( walk(f) ) | f
else f
end;

有关更多详细信息和示例,请参阅 jq 手册的“开发”版本,jq FAQ https://github.com/stedolan/jq/wiki/FAQ

“数组元素内不允许重复”

这很容易使用 index/1 完成;您可能喜欢使用辅助函数,例如:

def ensure_has($x): if index([$x]) then . else . + [$x] end;

“如果 .name 的任何父项不存在,应该能够即时添加它们”

如果我正确理解了这个要求,那么知道 jq 将基于赋值创建对象将对您很有用,例如

{} | .a.b.c = 1

产量

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

因此,使用您的示例,您可能希望在您的walk 中包括这样的内容:

if type == "object" and has("spec")
then (.spec.template.spec.containers? // null) as $existing
| if $existing then .spec.template.spec.containers |= ...
else .spec.template.spec.containers = ...
end
else .
end

关于json - jq 1.5 - 更改现有元素或添加新元素(如果不存在),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49014616/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com