如何使用 jq 排除 JSON 中具有特定值的所有键?

如何使用 jq 排除 JSON 中具有特定值的所有键?

假设我有一个如下所示的 JSON:

{
    "key1": {
        "keyA": "1",
        "keyB": "null",
        "keyC": "null"
    },
    "key2": {
        "keyA": "null",
        "keyB": "3",
        "keyC": "null"
    }
}

我想找到一种方法来排除nullJSON 中具有值的所有键。所以结果如下:

{
    "key1": {
        "keyA": "1"
    },
    "key2": {
        "keyB": "3"
    }
}

我知道我可以使用 排除特定键及其名称jq,例如cat myjson.json | jq 'del(.[]|.keyA)',这将删除keyAjson 中的所有键,但我想根据它们的值排除键...如何使用 排除所有具有值的"null"jq

答案1

del(..|select(. == "null"))

这使用了递归下降运算符..select功能查找对象中任何位置的所有位置,其值等于"null"并将它们赋予delselect评估布尔表达式来决定是否包含特定值,同时..将树中的每个值赋予它,并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

相关内容