如何使用jq的unique_by基于两个键去重并保留其他字段?
基于多键(name+url)的JSON数组去重方案
问题描述
我了解如何通过单个键实现去重,使用的是
unique_by('.[].name')。现在我希望基于两个键(如name和url)进行去重,同时保留输入中的其他字段,请问该如何操作?示例输入:
[ { "name": "abc", "url": "https://aa.com", "created_at": "2022-09-30T11:17:33.181Z" }, { "name": "bb", "url": "https://ddd.com", "created_at": "2022-09-30T11:14:33.180Z" }, { "name": "abc", "url": "https://aa.com", "created_at": "2022-09-30T11:14:33.180Z" } ]预期输出:
[ { "name": "abc", "url": "https://aa.com", "created_at": "2022-09-30T11:17:33.181Z" }, { "name": "bb", "url": "https://ddd.com", "created_at": "2022-09-30T11:14:33.180Z" } ]
解决方案
基础去重(保留首次出现的对象)
直接给unique_by传入一个生成复合键的表达式,把需要作为判断依据的两个字段组合成数组即可:
jq 'unique_by([.name, .url])' input.json
原理很直接:[.name, .url]会为每个对象生成一个包含name和url的数组,unique_by会基于这个复合数组判断对象是否重复——只要两个对象的name和url完全一致,就会被判定为重复项,最终只保留数组中首次出现的那个对象,同时完整保留该对象的所有其他字段(比如示例里的created_at)。
进阶:保留最新的对象
如果需要在重复组中保留created_at时间最新的对象,可以先按时间排序再去重:
jq 'sort_by(.created_at | fromdateiso8601) | reverse | unique_by([.name, .url])' input.json
步骤拆解:
sort_by(.created_at | fromdateiso8601):把所有对象按created_at时间升序排列(最早的在前)reverse:反转数组,让最新的对象排在前面unique_by([.name, .url]):此时去重会保留每个重复组中排在最前面的最新对象
内容的提问来源于stack exchange,提问作者kingsec
相关产品推荐
相关产品推荐

