使用 jq 修改 JSON 中的值:在值前面加上父键的名称

Modify value in JSON with jq: prepend value with name of parent key

我的想法是我有一个对象,它是数组的一部分,它本身就是父键的值。我想使用该键的值来更改原始子对象中的值。

这是我想出的办法,虽然它有效,但我不禁认为还有更好的方法。这太不直观了,我至少花了 3 个小时的试验结束错误来确定语法并删除错误。

echo '{"red": [{"fruit": "apple", "grows_on":"tree"}, {"fruit":"raspberry","grows_on":"vine"}], "green": [{"fruit": "apple", "grows_on":"tree"}, {"fruit":"gooseberry","grows_on":"bush"}]}' | 
jq '
  walk(
    if type=="object" then 
      with_entries(
        if .key == "red" then
          with_entries(
            walk(
              if type=="object" then 
                with_entries(
                  if .key=="fruit" then 
                    .value= "red" + "_" + .value 
                  else . end
                ) 
              else . end
            )
          )
        elif .key == "green" then
          with_entries(
            walk(
              if type=="object" then 
                with_entries(
                  if .key=="fruit" then 
                    .value= "green" + "_" + .value 
                  else . end
                ) 
              else . end
            )
          ) 
        else . end
      )
    else . end
  )'

{
  "red": [
    {
      "fruit": "red_apple",
      "grows_on": "tree"
    },
    {
      "fruit": "red_raspberry",
      "grows_on": "vine"
    }
  ],
  "green": [
    {
      "fruit": "green_apple",
      "grows_on": "tree"
    },
    {
      "fruit": "green_gooseberry",
      "grows_on": "bush"
    }
  ]
}

您可以使用 with_entries(它本身是 to_entries | map(…) | from_entries 的快捷方式)将每个字段解构为 key-value 对,通过访问键和值来根据自己的喜好进行操作,并再次重建它。 内部过滤器将键保存到一个变量中,下降到每个值的 fruit 并根据键及其当前名称 ..

更新其名称 |=
jq 'with_entries(.key as $key | .value[].fruit |= $key + "_" + .)'
{
  "red": [
    {
      "fruit": "red_apple",
      "grows_on": "tree"
    },
    {
      "fruit": "red_raspberry",
      "grows_on": "vine"
    }
  ],
  "green": [
    {
      "fruit": "green_apple",
      "grows_on": "tree"
    },
    {
      "fruit": "green_gooseberry",
      "grows_on": "bush"
    }
  ]
}

Demo

如果您只想更新名为 redgreen 的 top-level 对象的字段,以及名为 fruit 的值数组的对象项的字段(这是您的检查正在进行),您可以结合使用 objects(这是 select(type == "object") 的快捷方式)和适当的检查。

jq '
  objects |= with_entries(.key as $key | if IN("red", "green"; $key) then
    (.value[] | objects.fruit // empty) |= $key + "_" + . 
  else . end)
'

Demo