使用 jq 更新对象中其他字段标识的数组元素

Updating an array element identified by other fields in the object using jq

目标

我想在我的 kubeconfig 文件的当前活动 clusters 条目中添加一个 proxy-url 字段。 “活动”集群由“活动”上下文标识,“活动”上下文本身由顶级键 current-context 标识。简化后,JSON 对象类似于:

{
  "clusters":[
    {
      "name":"cluster1",
      "field":"field1"
    },
    {
      "name":"cluster2",
      "field":"field2"
    }
  ],
  "contexts":[
    {
      "name":"context1",
      "context": {
        "cluster":"cluster1"
      }
    },
    {
      "name":"context2",
      "context": {
        "cluster":"cluster2"
      }
    }
  ],
  "current-context": "context1"
}

我想更新 cluster1clusters 条目来自:

{
  "name":"cluster1",
  "field":"field1"
}

{
  "name":"cluster1",
  "field":"field1",
  "proxy-url":"my-url"
}

第一次尝试

jq '. as $o
  | $o."current-context" as $current_context_name
  | $o.contexts[] | select(.name == $current_context_name) as $context
  | $o.clusters[] | select(.name == $context.context.cluster)
  | .proxy_id |= "my-url"'

给我

{
  "name": "cluster1",
  "field": "field1",
  "proxy_id": "my-url"
}

-- 太棒了!但我也需要对象的其余部分。

括号几乎可以工作

使用括号,我可以取回整个对象并向活动 context 添加一个“proxy-url”字段,但我不能接受进一步更新活动 集群 。此过滤器:

jq '(. as $o
  | $o."current-context" as $current_context_name
  | $o.contexts[] | select(.name == $current_context_name)
  | ."proxy-url")
  |= "my-url"'

作品薄荷:

{
  "clusters": [...],  // omitted for brevity, unchanged
  "contexts": [
    {
      "name": "context1",
      "context": {
        "cluster": "cluster1"
      },
      "proxy-url": "my-url"  // tada!
    },
    {...}  // omitted for brevity, unchanged
  ],
  "current-context": "context1"
}

尝试更进一步(改为更新由 context 标识的 cluster):

jq '(. as $o
  | $o."current-context" as $current_context_name
  | $o.contexts[] | select(.name == $current_context_name) as $context
  | $o.clusters[] | select(.name == $context.context.cluster)
  | ."proxy-url")
  |= "my-url"'

给我以下错误:

jq: error (at <stdin>:26): Invalid path expression near attempt to access element "clusters" of {"clusters":[{"name":"clus...
exit status 5

如何使用 $context.context.cluster 结果更新相关的 clusters 条目?我不明白为什么这种方法适用于向 contexts 添加内容但不适用于 clusters.

肮脏的解决方案

我可以拼凑一个新的 clusters 条目并将其与顶级对象合并:

jq '. as $o
  | $o."current-context" as $current_context_name
  | $o.contexts[] | select(.name == $current_context_name) as $context
  | $o + {"clusters": [($o.clusters[] | select(.name == $context.context.cluster)."proxy-url" |= "my-url")]}

但这感觉有点脆弱。

此解决方案使用 INDEX 构造检索活动集群,然后直接设置新字段而不修改上下文:

jq '
  INDEX(.contexts[]; .name)[."current-context"].context.cluster as $cluster
  | (.clusters[] | select(.name == $cluster))."proxy-url" = "my-url"
'
{
  "clusters": [
    {
      "name": "cluster1",
      "field": "field1",
      "proxy-url": "my-url"
    },
    {
      "name": "cluster2",
      "field": "field2"
    }
  ],
  "contexts": [
    {
      "name": "context1",
      "context": {
        "cluster": "cluster1"
      }
    },
    {
      "name": "context2",
      "context": {
        "cluster": "cluster2"
      }
    }
  ],
  "current-context": "context1"
}

Demo