使用 yq 将 YAML 合并到特定的数组条目中
Merge YAML into specific array entry with yq
给定 master.yml ...
containers:
- name: project-a
items:
- CCC
- name: project-z
items:
- CCC
- DDD
... 和 update.yml ...
- name: project-z
items:
- CCC
- EEE
...我想将其合并到正确的条目中。这将给出:
containers:
- name: project-a
items:
- CCC
- name: project-z
items:
- CCC
- DDD
- EEE
以下 yq 4 有效 如果更新是针对 project-a
yq ea 'select(fileIndex==0) * {"containers":select(fileIndex==1)}' master.yml update.yml
但是,使用提供的 project-z
更新,它错误地替换了第一个数组条目(你最终得到两个 project-z
s)。
深入阅读手册后,我得到了这个:
yq ea 'select(fi==1).0.name as $p | (select(fi==0).containers.[] | select(.name==$p)) = (select(fi==1) | .0 | . headComment="AUTO-UPDATED") | select(fi==0)' master.yml update.yml
通过首先搜索 name
匹配 update.yml
然后完全替换内容来替换而不是合并 project-z
。
我理解数据被格式化为 list 的根本原因应该是 dictionary (name
是独一无二)。
这会很简单地合并,将来也会更好!
containers:
project-a:
items:
- CCC
project-z:
items:
- CCC
- DDD
- EEE
这类似于另一个 Whosebug 问题,其中 kev 有一个非常巧妙的解决方案(我认为)。
我已将他的解决方案添加到此处的 yq 文档:https://mikefarah.gitbook.io/yq/operators/multiply-merge#merge-arrays-of-objects-together-matching-on-a-key
在您的情况下,这仅在第二个文件与第一个文件的结构匹配时才有效(也就是说,它也有 'containers' 作为父文件):
yq eval-all '
(
((.containers[] | {.name: .}) as $item ireduce ({}; . *+ $item )) as $uniqueMap
| ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value)
) as $mergedArray
| select(fi == 0) | .containers = $mergedArray
` file.yaml file2.yaml
containers:
- name: project-a
items:
- CCC
- name: project-z
items:
- CCC
- DDD
- CCC
- EEE
基本上它的工作原理是根据名称缩减为合并映射(正如您提到的那样,如果已经是这种情况会容易得多),然后将其转换回数组。
免责声明:我写了yq
给定 master.yml ...
containers:
- name: project-a
items:
- CCC
- name: project-z
items:
- CCC
- DDD
... 和 update.yml ...
- name: project-z
items:
- CCC
- EEE
...我想将其合并到正确的条目中。这将给出:
containers:
- name: project-a
items:
- CCC
- name: project-z
items:
- CCC
- DDD
- EEE
以下 yq 4 有效 如果更新是针对 project-a
yq ea 'select(fileIndex==0) * {"containers":select(fileIndex==1)}' master.yml update.yml
但是,使用提供的 project-z
更新,它错误地替换了第一个数组条目(你最终得到两个 project-z
s)。
深入阅读手册后,我得到了这个:
yq ea 'select(fi==1).0.name as $p | (select(fi==0).containers.[] | select(.name==$p)) = (select(fi==1) | .0 | . headComment="AUTO-UPDATED") | select(fi==0)' master.yml update.yml
通过首先搜索 name
匹配 update.yml
然后完全替换内容来替换而不是合并 project-z
。
我理解数据被格式化为 list 的根本原因应该是 dictionary (name
是独一无二)。
这会很简单地合并,将来也会更好!
containers:
project-a:
items:
- CCC
project-z:
items:
- CCC
- DDD
- EEE
这类似于另一个 Whosebug 问题,其中 kev 有一个非常巧妙的解决方案(我认为)。
我已将他的解决方案添加到此处的 yq 文档:https://mikefarah.gitbook.io/yq/operators/multiply-merge#merge-arrays-of-objects-together-matching-on-a-key
在您的情况下,这仅在第二个文件与第一个文件的结构匹配时才有效(也就是说,它也有 'containers' 作为父文件):
yq eval-all '
(
((.containers[] | {.name: .}) as $item ireduce ({}; . *+ $item )) as $uniqueMap
| ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value)
) as $mergedArray
| select(fi == 0) | .containers = $mergedArray
` file.yaml file2.yaml
containers:
- name: project-a
items:
- CCC
- name: project-z
items:
- CCC
- DDD
- CCC
- EEE
基本上它的工作原理是根据名称缩减为合并映射(正如您提到的那样,如果已经是这种情况会容易得多),然后将其转换回数组。
免责声明:我写了yq