jq删除重复的对象之一

时间:2018-07-31 17:53:06

标签: json linux jq

我有一个像这样的json文件:

{"caller_id":"123321","cust_name":"abc"}
{"caller_id":"123443","cust_name":"def"}
{"caller_id":"123321","cust_name":"abc"}
{"caller_id":"234432","cust_name":"ghi"}
{"caller_id":"123321","cust_name":"abc"}
....

我尝试过:

jq -s 'unique_by(.field1)' 

但是这将删除所有重复项,我希望仅保留其中一项,以获取如下文件:

{"caller_id":"123321","cust_name":"abc"}
{"caller_id":"123443","cust_name":"def"}
{"caller_id":"234432","cust_name":"ghi"}
....

2 个答案:

答案 0 :(得分:0)

对于Path=,我怀疑您是否在输出中得到了任何东西,因为没有给定名称的键/字段。如果仅将命令更改为field1,它将为您提供所需的结果,其中包含基于jq -s 'unique_by(.caller_id)'键的唯一且经过排序的对象。这样可以确保每个caller_id至少有一个对象。

注意:与@Jeff Mercado在评论中解释的内容相同。

答案 1 :(得分:0)

如果文件由JSON对象的序列(流)组成,则产生不同对象流的一种非常简单的方法是使用调用:

jq -s `unique[]`

一个类似的选择是:

jq -n `[inputs] | unique[]`

但是,对于大文件,无论是在RAM还是在运行时上,上述效率可能都太低了。请注意,uniqueunique_by都需要排序。

更好的选择是利用输入是流这一事实,并避免使用内置的uniqueunique_by过滤器。可以在以下过滤器的帮助下完成此操作,这些过滤器尚未内置但有可能成为内置过滤器:

# emit a dictionary
def set(s): reduce s as $x ({}; .[$x | (type[0:1] + tostring)] = $x);

# distinct entities in the stream s
def distinct(s): set(s)[];

我们现在只需添加:

distinct(inputs)

要实现该目标,只要使用-n命令行选项调用jq。

这种方法还将保留原始顺序。

如果输入是数组...

如果输入是数组,则使用上面定义的distinct仍然具有不需要排序的优点。对于太大而无法舒适地容纳在内存中的阵列,建议使用jq的流解析器来创建流。

一种可能是分两个步骤(jq --stream .... | jq -n ...)进行,但最好使用以下“主”程序一步完成(jq -cn --stream ...):

distinct(fromstream(inputs 
                    | (.[0] |= .[1:] )
                    | select(. != [[]])))