在jq中替换没有确切路径的子项

时间:2016-12-27 19:10:02

标签: json nested key updates jq

示例JSON文件:

{
  "u": "stuff",
  "x": [1,2,3],
  "y": {
    "field": "value"
  },
  "z": {
    "zz": {
       "name": "change me",
       "more": "stuff"
    },
    "randomKey":  {
       "name": "change me",
       "random": "more stuff"
    }
  }
}

如何将所有名称字段更新为"",保持JSON文件的其余部分相同?

{
  "u": "stuff",
  "x": [1,2,3],
  "y": {
    "field": "value"
  },
  "z": {
    "zz": {
       "name": "something",
       "more": "stuff"
    },
    "randomKey":  {
       "name": "something",
       "random": "more stuff"
    }
  }
}

使用直接路径,这很容易,但父键(在这种情况下为z和randomKey)会有所不同。

我尝试过类似的事情:

jq '.z | .. | .name? |= "something"' file.json

它更新了名称,但也放了所有递归的东西..

2 个答案:

答案 0 :(得分:1)

如果可以在任何地方更改“名称”字段,则可以使用walk/1

walk(if type == "object" and has("name") then .name = "something" else . end)

请注意,在jq 1.5发布后,walk/1仅包含在jq中。如果您的jq没有它,那么您可以在jq FAQ上找到它的定义。

如果您只想修改“z”上下文中的“name”字段,请考虑:

.z |= with_entries(if .value.name?
                   then .value.name = "something" 
                   else . end)

答案 1 :(得分:1)

假设z中的每个值都有name属性,您可以这样做:

$ jq --arg newname 'something' '.z[].name = $newname' input.json

在对象上使用[]将产生该对象中包含的所有值。对于每个值,我们只是将name设置为新名称。

如果您需要对更新内容更具选择性,则必须为要更新的对象添加更多条件。一般来说,我使用峰值方法,但这是使用类似于第一种方法的结构可以实现的另一种方式,假设我们只想更新已经有{{{}的对象。 1}} property:

name

将作业的LHS包含在括号中非常重要,我们不希望在作业之前更改上下文,否则我们不会看到其余结果。< / p>