jq,在任何级别上替换null值,不接触非null或不存在



请协助jq.中的新手:(

我必须更新一个具有特定名称的字段,该字段可能出现在任何级别的JSON结构上,也可能不会。与下面JSON中的所有*.description字段类似:

{
"a": {
"b": [{
"name": "b0",
"description": "b0 has description"
},
{
"name": "b1",
"description": null
},
{
"name": "b2"
}
],
"description": null
},
"s": "Some string value"
}

我需要用一些伪值更新"描述"值,如果它只有null值,但不要接触现有值,也不要在不存在的地方创建新字段。因此,在这种情况下,期望的结果是:

{
"a": {
"b": [{
"name": "b0",
"description": "b0 has description"
},
{
"name": "b1",
"description": "DUMMY DESCRIPTION"
},
{
"name": "b2"
}
],
"description": "DUMMY DESCRIPTION"
},
"s": "Some string value"
}

在这里,.a.b[0].description保持不变,因为它存在并且不是null。a.b[1].description和.a.description被强制为"假人描述",因为这些字段存在并且为空;和.a.b[2]以及根级别保持不变,因为根本没有描述字段。

例如,如果我尝试在已知路径上使用命令,如下面的

jq '.known.level.description //= "DUMMY DESCRIPTION"' ........

它无法跳过.a.b[2].description等不存在的字段;当然,它只适用于JSON中的已知位置。如果我尝试做递归搜索,比如:

jq '.. | .description? //= "DUMMY DESCRIPTION"' ........

它似乎无法在数组上正常工作。

在这种情况下,遍历整个JSON的正确方法是什么?谢谢

在这种情况下,遍历整个JSON的正确方法是什么?

答案是walk

如果你的jq还没有walk/1,你可以很容易地在谷歌上搜索它(jq"defwalk"(,然后在使用它之前包括它的def,例如:

walk(if type == "object" and has("description") and .description == null
then .description = "DUMMY DESCRIPTION"
else . end)

您可以考虑的一个选项是使用流。您将获得输入中每个项目的路径和值。这样,您就可以查找名称为"description"的名称/值对并更新值。

$ jq --arg replacement "DUMMY DESCRIPTION" '
fromstream(tostream | if length == 2 and .[0][-1] == "description"
then .[1] |= (. // $replacement)
else .
end)
' input.json

最新更新