如何使用yq对YAML数组执行upsert更新插入操作
问题描述
现有如下hello.yaml文件内容:
foos: - foo: foo1 bar: hello - foo: foo2 bar: world
已知更新foo = "foo1"对应条目的bar字段,可执行如下命令:
yq '( .foos[] | select(.foo == "foo1") | .bar) |= "goodbye cruel"' hello.yaml
命令执行后输出正确的更新结果:
foos: - foo: foo1 bar: goodbye cruel - foo: foo2 bar: world
现在需要实现数组的upsert效果:无法提前确认匹配条目是否存在时,匹配到对应条目就更新字段,匹配不到就插入符合要求的新条目。例如操作foo = "foo3"时,自动输出追加新条目的结果:
foos: - foo: foo1 bar: hello - foo: foo2 bar: world - foo: foo3 bar: goodbye cruel
核心疑问:yq是否原生支持这类数组upsert操作,还是必须预先判断目标键是否存在,再分开执行插入、更新两类命令?
解答
目前常用的Go版本yq(v4及以上)支持单条命令完成数组upsert,不需要额外在shell层做存在性判断,也不需要拆分更新、插入两条命令分别执行。
直接在yq表达式内完成分支判断即可,参考命令如下:
yq ' (any(.foos[]; .foo == "foo3")) as $exists | if $exists then (.foos[] | select(.foo == "foo3") | .bar) = "goodbye cruel" else .foos += {"foo": "foo3", "bar": "goodbye cruel"} end ' hello.yaml
命令执行效果:
- 传入已存在的
foo值(比如foo1、foo2)时,会直接定位到对应条目更新bar字段,和原有更新命令的行为完全一致 - 传入不存在的
foo值(比如foo3)时,会自动把构造好的新条目追加到foos数组末尾,实现插入效果
如果需要精简写法,也可以用下面的短命令,逻辑完全一致:
yq '(.foos[] | select(.foo=="foo3") | .bar) = "goodbye cruel" | .foos += (any(.foos[]; .foo=="foo3") | not) as $need | if $need then {"foo":"foo3","bar":"goodbye cruel"} else empty end' hello.yaml
内容的提问来源于stack exchange,提问作者Jimmy The Dog
相关产品推荐
相关产品推荐

