我正在尝试使用jq从JSON对象中删除空值。 我在他们的GitHub上发现了此问题,因此现在我正在尝试使用del
将它们删除。
我有这个:
'{ id: $customerId, name, phones: ([{ original: .phone },
{ original: .otherPhone}]), email} | del(. | nulls)'
这似乎没有任何作用。然而,如果我将nulls
替换为.phones
,它会删除电话号码。
这个答案是由Michael Homer在https://unix.stackexchange.com上提供的,它提供了一个超级简洁的解决方案,适用于jq 1.6及以上版本:
del(..|nulls)
它会从你的JSON中删除所有空值属性(和值)。简单而甜美 :)
nulls
是一个内置过滤器,可以被自定义选择替换:
del(..|select(. == "value to delete"))
为了根据多个条件删除元素,例如删除所有布尔值和所有数字:
del(..|booleans,numbers)
del(..|select(. == "value to keep" | not))
== 和 != ,但有时这是不可能的。例如,要保留所有真值:del(.. | select(. | not))
)
jq 'del(recurse(.[]?;true)|select(. == null))'
适用于版本1.5,我已经成功使用了。 - Skippy le Grand Gouroujq -n '{"a":1, "b": null, "c": null} | with_entries( select( .value != null ) )'
{
"a": 1
}
或者,可以按照以下方式使用paths/0
:
. as $o | [paths[] | {(.) : ($o[.])} ] | add
顺便提一下,del/1
也可以用来实现同样的结果,例如使用这个过滤器:
reduce keys[] as $k (.; if .[$k] == null then del(.[$k]) else . end)
或者更为简洁,但不那么明显的是:
del( .[ (keys - [paths[]])[] ] )
同时,以下是使用delpaths/1
的两种方式:
jq -n '{"a":1, "b": null, "c": null, "d":2} as $o
| $o
| delpaths( [ keys[] | select( $o[.] == null ) ] | map( [.]) )'
$ jq -n '{"a":1, "b": null, "c": null, "d":2}
| [delpaths((keys - paths) | map([.])) ] | add'
在以上两种情况下,输出结果相同: { "a": 1, "d": 2 }
参考资料:如果您想从JSON文本中的所有JSON对象中删除空值键(即递归地),您可以使用walk/1
或:
del(.. | objects | (to_entries[] | select(.value==null) | .key) as $k | .[$k])
del/1
这样的函数引用中,/1
是什么意思?我在其他答案中也看到过它,但在 jq 的文档中没有找到相关说明。 - Mr. Lance E Sloanbuiltins
的内置函数,它会发出一个字符串数组,形式为FUNCTOR/ARITY。 - peak$ jq 'walk( if type == "object" then with_entries(select(.value != null)) else . end)' input.json
参考来自于在上游讨论增加walk()
函数问题时的此评论。
walk/1
定义存在问题,特别是第一条评论中提到的原因;还要注意,jq 1.6以不同方式定义walk/1
]。 我添加新答案以强调@ jeff-mercado扩展版本脚本。 我的脚本版本假定空值如下:
null
;[]
- 空数组;{}
- 空对象。删除空数组和对象的代码来自于此处https://dev59.com/O18e5IYBdhLWcg3wAWgL#26196653。
def walk(f):
. as $in |
if type == "object" then
reduce keys[] as $key
( {}; . + { ($key): ( $in[$key] | walk(f) ) } ) | f
elif type == "array" then
select(length > 0) | map( walk(f) ) | f
else
f
end;
walk(
if type == "object" then
with_entries(select( .value != null and .value != {} and .value != [] ))
elif type == "array" then
map(select( . != null and . != {} and .!= [] ))
else
.
end
)
def walk(f)
中添加 select(length > 0) |
是一个错误。对于某些 JSON,它会删除非空数组。对于其他 JSON(例如,嵌套对象,每个对象包含一些 null 和空结构),只返回 {}
。然而,这里显示的条件与 walk
的原始定义相匹配。我刚刚注意到这个问题,所以我无法更改昨天的投票。 - Mr. Lance E Sloan这并不是 del/1
函数的正确使用方式。如果你想要移除一个对象的 .phones
属性,你应该这样做:
del(.phones)
del
的参数是您想要删除的属性路径。null
值的路径并将其传递给该方法。但这可能比较麻烦。fromstream(tostream | select(length == 1 or .[1] != null))
null
值。如果发现,就将其过滤掉。使用walk/1
,你可以递归地应用过滤器来排除null
值。walk(
(objects | with_entries(select(.value != null)))
// (arrays | map(select(. != null)))
// values
)
因此,如果您有以下输入:
{
"foo": null,
"bar": "bar",
"biz": [1,2,3,4,null],
"baz": {
"a": 1,
"b": null,
"c": ["a","b","c","null",32,null]
}
}
{
"bar": "bar",
"baz": {
"a": 1,
"c": ["a","b","c","null",32]
},
"biz": [1,2,3,4]
}
def traverse(f):
if type == "object" then map_values(traverse(f)) | f
elif type == "array" then map( traverse(f) ) | f
else f
end;
def isempty: .==null or ((type|(.=="array" or .=="object")) and length==0);
traverse(select(isempty|not))
[警告:下面的响应存在几个问题,其中最主要的是由于0|length
为0而引起的。]
在早期答案的基础上,除了删除具有null
值的属性外,还经常有助于删除具有空数组或对象值(即[]
或{}
)的JSON属性。
ℹ️ — jq的
walk()
函数(walk/1
)使此操作变得容易。walk()
将在未来版本的jq(>jq-1.5
)中提供,但其定义可以添加到当前过滤器中。
用于删除null和空结构的条件是:
walk(
if type == "object" then with_entries(select(.value|length > 0))
elif type == "array" then map(select(length > 0))
else .
end
)
给定以下 JSON 输入:
{
"notNullA": "notNullA",
"nullA": null,
"objectA": {
"notNullB": "notNullB",
"nullB": null,
"objectB": {
"notNullC": "notNullC",
"nullC": null
},
"emptyObjectB": {},
"arrayB": [
"b"
],
"emptyBrrayB": []
},
"emptyObjectA": {},
"arrayA": [
"a"
],
"emptyArrayA": []
}
{
"notNullA": "notNullA",
"objectA": {
"notNullB": "notNullB",
"objectB": {
"notNullC": "notNullC"
},
"arrayB": [
"b"
]
},
"arrayA": [
"a"
]
}
jq'...your code here...'<<'EOF'
,包括一些演示问题的JSON,并在之后加上EOF
)。另请参阅帮助中心有关最小完整可验证示例的文档。 - Charles Duffy