Update a specific object value under YAML based on a condition using yq
Asked Answered
yq
E

1

12

Using https://github.com/mikefarah/yq v4

Given a sample.yaml file like this:

spec:
  chart:
    name: my-chart
    version: 0.0.1
---
spec:
  chart:
    name: something-else
    version: 0.0.2

I want to update the version value but only for the instance of .spec.chart.version where the sibling .spec.chart.name element == my-chart. The result would need to output the entire yaml file so that I can edit the YAML file inline.

If I use a select like

yq e -i 'select(.spec.chart.name == "my-chart") | .spec.chart.version = "1.0.0"' sample.yaml

The second instance of .spec has been removed:

spec:
  chart:
    name: my-chart
    version: 1.0.0

Any advice?

Equiangular answered 21/9, 2021 at 17:16 Comment(2)
The idea is right, but you need to use the Update assignment operator |= to perform the update on the selected object, i.e. yq e 'select(.spec.chart.name == "my-chart").spec.chart.version |= "1.0.0"' yamlHake
The above suggestion does not work. The problem is that select is a filter. If the chart name doesn't match, the node is dropped. What we really need here is a conditional update (not a filter).Redstone
M
24
yq '(.spec.chart | select(.name == "my-chart") | .version) = "1.0"' file.yaml

Explanation:

  • First we want to find all the (potential) nodes we want to update, in this case, it's .spec.chart.
  • Next we filter out those node to be only the ones we're interested in, select(.name == "my-chart")
  • Now we select the field we want to update .version
  • Importantly, the whole LHS is in brackets, so those matching version nodes are passed to the update (=) function. If you don't do this, then the filter happens before (and separately to) the update - and so you only see filtered results.

Disclaimer: I wrote yq

Mingy answered 29/6, 2022 at 4:47 Comment(6)
I had a similar problem, and this solution resolved it. Thank you!Tartarean
@Mingy how can I update yq '(.spec.chart.version) = "1.0"' file.yaml for first or some n-th document in yaml file ?Russom
hmm.. got it.. yq '(select(documentIndex == 1) | .spec.chart.version) = "1.0"' file.yaml thanks for the yq ..Russom
@Mingy how can I update the version to be dependent on another value in that spec and not hardcoded value? I tried something like this yq '(select(documentIndex == 1) | .spec.chart.version) = .spec.otherproperty file.yaml but it always grabs the value of the last .spec.otherpropertyCopland
@Rafi, in that case I'd use a with block (see mikefarah.gitbook.io/yq/operators/with) and do :yq 'with(.spec.chart | select(.name == "my-chart"); .version = .other)'Mingy
Awesome @mike.f! Thank you so much! I spent several hours trying to figure out how to see all results instead of filtered ones. Hope this could be explained better in the docs.Sampling

© 2022 - 2024 — McMap. All rights reserved.