我正在尝试使用jq从json对象中删除空值。我在他们的github上找到this issue,所以现在我试图用del
删除它们。
我有这个:
'{ id: $customerId, name, phones: ([{ original: .phone },
{ original: .otherPhone}]), email} | del(. | nulls)'
这似乎没有做任何事情。但是,如果我将nulls
替换为.phones
,则会删除电话号码。
答案 0 :(得分:6)
以下说明如何从JSON对象中删除所有空值键:
jq -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 }
答案 1 :(得分:2)
那不是del/1
的意思。给定一个对象作为输入,如果您想删除.phones
属性,您可以这样做:
del(.phones)
换句话说,del
的参数是您要删除的属性的路径。
如果你想使用它,你必须找出null
值的所有路径并将其传递给它。那会更麻烦。
为了更简单的方法,您必须遍历对象树以查找null
值。如果找到,请删除相应的属性(或以其他方式将其过滤掉)。使用walk/1
,您的过滤器可以递归应用,以排除null
值。
walk(
if type == "object" then
with_entries(select(.value != null))
elif type == "array" then
map(select(. != null))
else
.
end
)
所以,如果你有这个输入:
{
"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]
}
walk/1
将在未来版本的jq中添加,因此您必须添加它。您可以获取定义here。
# Apply f to composite entities recursively, and to atoms
def walk(f):
. as $in
| if type == "object" then
reduce keys_unsorted[] as $key
( {}; . + { ($key): ($in[$key] | walk(f)) } ) | f
elif type == "array" then map( walk(f) ) | f
else f
end;
答案 2 :(得分:2)
[警告:此回复中给出的walk/1
的定义存在问题,尤其是出于第一条评论中给出的原因;另请注意,jq 1.6以不同的方式定义walk/1
。]
我正在添加新答案,以强调@ jeff-mercado的脚本扩展版本。我的脚本版本假设空值如下:
null
; []
- 空数组; {}
- 空对象。 从这里https://stackoverflow.com/a/26196653/3627676借用了删除空数组和对象。
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
)
答案 3 :(得分:1)
您可以使用此表达式递归删除空值键:
jq 'walk( if type == "object" then with_entries(select(.value != null)) else . end)'
答案 4 :(得分:0)
[警告:以下回复有几个问题,尤其是因$ans = preg_match_all("/\b$now $next\b/ui", $text_file);
// here __^
为0而引起的问题。]
对earlier answer进行阐述,除了删除具有0|length
值的属性外,删除具有空数组或对象值的JSON属性(即null
或{{1}通常很有帮助也是。
ℹ️ - jq的
[]
函数({}
)使这很容易。walk()
将是。{ 在jq(>walk/1
)的未来版本中可用,但its definition 可以添加到当前过滤器。
传递给walk()
以删除空值和空结构的条件是:
jq-1.5
鉴于此JSON输入:
walk()
使用此功能可得出结果:
walk(
if type == "object" then with_entries(select(.value|length > 0))
elif type == "array" then map(select(length > 0))
else .
end
)
答案 5 :(得分:0)
在此页面的其他地方,人们表达了一些兴趣 使用jq消除[]和{}以及null的递归出现。
尽管可以使用walk/1
的内置定义来执行
这样,正确执行此操作有点棘手。因此,这里是一个变体版本
的walk/1
中,这样做很简单:
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))
答案 6 :(得分:0)
到目前为止,所有其他答案都是旧版本jq
的变通办法,目前尚不清楚如何在最新发行的版本中做到这一点。在JQ 1.6或更高版本中,这将以递归方式删除null:
$ jq 'walk( if type == "object" then with_entries(select(.value != null)) else . end)' input.json
来自this comment,是在上游讨论添加walk()
函数的问题。
答案 7 :(得分:0)
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))
(最后一个例子只是说明性的——当然你可以将 ==
换成 !=
,但有时这是不可能的。例如,保留所有真值:{ {1}})