假设我有一个如下所示的 JSON:
{
"key1": {
"keyA": "1",
"keyB": "null",
"keyC": "null"
},
"key2": {
"keyA": "null",
"keyB": "3",
"keyC": "null"
}
}
我想找到一种方法来排除null
JSON 中具有值的所有键。所以结果如下:
{
"key1": {
"keyA": "1"
},
"key2": {
"keyB": "3"
}
}
我知道我可以使用 排除特定键及其名称jq
,例如cat myjson.json | jq 'del(.[]|.keyA)'
,这将删除keyA
json 中的所有键,但我想根据它们的值排除键...如何使用 排除所有具有值的"null"
键jq
?
答案1
del(..|select(. == "null"))
这使用了递归下降运算符..
和select
功能查找对象中任何位置的所有位置,其值等于"null"
并将它们赋予del
。select
评估布尔表达式来决定是否包含特定值,同时..
将树中的每个值赋予它,并del
接受任何生成位置的表达式,这就是这样做的。 (演示)
您可以使用该path
函数来检查它发现了什么:
path(..|select(. == "null"))
并调试它认为您要首先尝试删除的内容。这输出是一个键数组,要递归地达到该值,因此数组中的最后一项是实际要删除的键。
您还可以在 jq 1.6 及更高版本中使用更新分配|= empty
(在早期版本中它会默默地失败)。您可能会或可能不会发现这一点更清楚(..|select(. == "null")) |= empty
:(演示) 删除那些相同的键。
如果您的值是 true null
,而不是 string "null"
,您可以使用nulls
内置函数代替整个select
: del(..|nulls)
。
如果您的值是 true null和你正在使用jq 1.5(许多发行版中的当前版本),您需要使用 来recurse(.[]?; true)
代替..
.这是因为空值被明确排除在外..
(因为它被定义为recurse
, 哪个定义为 recurse(.[]?)
,其定义为recurse(.[]?; . != null)
)。不过,这种行为在 1.6 中更改为上面的(更有用的)行为文档没有改变,这似乎是一个文档错误。
答案2
假设您知道要测试第二级的值:
jq 'del(.[][] | select(. == "null"))' file
这会删除从顶部开始的第二层上的每个键值对,其中值是文字 string null
。
鉴于问题中的文档,这会产生预期的输出。
使用高于 1.5 的版本jq
,您还可以将数据更新为没有该null
值的位:
jq '.[][] |= select(. != "null")' file