6

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?

Inian
  • 80,270
  • 14
  • 142
  • 161
Crichard
  • 61
  • 1
  • 3
  • 2
    The idea is right, but you need to use the [Update assignment operator](https://mikefarah.gitbook.io/yq/operators/comment-operators#use-update-assign-to-perform-relative-updates) `|=` to perform the update on the selected object, i.e. `yq e 'select(.spec.chart.name == "my-chart").spec.chart.version |= "1.0.0"' yaml` – Inian Sep 26 '21 at 19:32
  • 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). – Mike Rizzo Jun 22 '22 at 17:18

1 Answers1

9
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

mike.f
  • 1,586
  • 13
  • 14
  • I had a similar problem, and this solution resolved it. Thank you! – l_smith Aug 19 '22 at 21:25
  • @mike.f how can I update `yq '(.spec.chart.version) = "1.0"' file.yaml` for first or some n-th document in yaml file ? –  Oct 03 '22 at 15:21
  • 2
    hmm.. got it.. `yq '(select(documentIndex == 1) | .spec.chart.version) = "1.0"' file.yaml` thanks for the yq .. –  Oct 03 '22 at 15:32
  • @mike.f 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.otherproperty – Rafi Feb 10 '23 at 10:48
  • 1
    @Rafi, in that case I'd use a `with` block (see https://mikefarah.gitbook.io/yq/operators/with) and do :`yq 'with(.spec.chart | select(.name == "my-chart"); .version = .other)'` – mike.f Feb 11 '23 at 13:01