使用 JQ 中更高级别对象的值更新深层嵌套字段

Update deeply nested field with value from higher-level object in JQ

给定以下输入 JSON:

{
  "version": 2,
  "models": [
    {
      "name": "first_table",
      "tests": [
        {
          "dbt_utils.equal_rowcount": {
            "compare_model": null
          }
        }
      ]
    },
    {
      "name": "second_table",
      "tests": [
        {
          "dbt_utils.equal_rowcount": {
            "compare_model": null
          }
        }
      ]
    }
  ]
}

我如何使用 jqnull(即 "compare_model" 的值)替换为 "name" 中的值key? 注意这里所说的键值对在层级上不在同一层级:前者嵌套在数组中的一个对象中,而与后者。

例如,输出文件应为:

{
  "version": 2,
  "models": [
    {
      "name": "first_table",
      "tests": [
        {
          "dbt_utils.equal_rowcount": {
            "compare_model": "first_table"
          }
        }
      ]
    },
    {
      "name": "second_table",
      "tests": [
        {
          "dbt_utils.equal_rowcount": {
            "compare_model": "second_table"
          }
        }
      ]
    }
  ]
}

FWIW,这是一些 YAML 的中间步骤(通过 yqjq 的 Python 包装器变体,而不是 go 变体)争论我在 DBT config files.

上做

(如果您可以用括号 and/or 将替换文本括起来而不用中断 jq 作为前缀,则会加分。:D 如果不行,不用担心——这一步我可以用另一个来做程序。)

不用多说,非常感谢您的帮助!


字段不在同一级别在这里并不重要。

.models[] |= (.tests[]."dbt_utils.equal_rowcount".compare_model = "(\(.name))")

Online demo

简单解决方案的关键是使用|=,例如

.models |= 
  map(.name as $name
      | (.tests[]."dbt_utils.equal_rowcount".compare_model =
         $name))

要将替换值括在括号中,只需添加它们:

.models |= 
  map("(\(.name))" as $name
      | (.tests[]."dbt_utils.equal_rowcount".compare_model =
         $name))

如果您希望替换以现有值为 null 为条件,您或许可以(取决于具体要求)使用 //=.

使用 //=walk

这是对这个问题的另一种看法:

.models
  |= map("(\(.name))" as $name
         | walk(if type=="object" and has("compare_model") 
                then .compare_model //= $name
                else . end))