使用jq在JSON对象中查找通用键

时间:2019-07-18 21:53:05

标签: json key jq set-intersection

鉴于我们不知道文件中键的名称,我试图在Json文件中查找所有通用键。

Json文件如下:

{
   "DynamicKey1" : {
    "foo" : 1,
    "bar" : 2

   },
   "DynamicKey2" : {
     "bar" : 3

   },
   "DynamicKey3" : {
     "foo" : 5,
     "zyx" : 5

   }   
}

预期结果:

{
 "foo"
}

我试图在这里应用reduce / foreach逻辑,但是我不确定如何在jq中编写它。感谢您的帮助!

jq '. as $ss | reduce range(1; $ss|length) as $i ([]; . + reduce ($ss[i] | keys) as $key ([]; if $ss[$i - 1] | has($key) then . +$key else . end))' file.json

3 个答案:

答案 0 :(得分:0)

在发布的Q中存在一些不一致之处:没有所有对象共有的键,并且如果查看键的成对相交,结果将同时包含“ foo”和“ bar”。 / p>

下面,我将针对这两个问题提出解决方案。

键入多个对象

[.[] | keys_unsorted[]] | group_by(.)[] | select(length>1)[0]

键入所有对象

这是使用类似方法的解决方案:

length as $length
| [.[] | keys_unsorted[]] | group_by(.)[]
| select(length==$length) 
| .[0]

这涉及group_by/2,它是使用排序实现的。

这里是一种替代方法,该方法依赖于内置函数keys进行排序(关键是(((nk ln(nk))-n(k ln(k)))= nk ln(n),即具有n个小项的k个项比一个较大的n * k个项要好):

# The intersection of an arbitrary number of sorted arrays
def intersection_of_sorted_arrays:
  # intersecting/1 returns a stream
  def intersecting($A;$B):
    def pop:
    .[0] as $i
    | .[1] as $j
    | if $i == ($A|length) or $j == ($B|length) then empty
      elif $A[$i] == $B[$j] then $A[$i], ([$i+1, $j+1] | pop)
      elif $A[$i] <  $B[$j] then [$i+1, $j] | pop
      else [$i, $j+1] | pop
      end;
    [0,0] | pop;
   reduce .[1:][] as $x (.[0]; [intersecting(.; $x)]);

要计算所有对象共有的键:

[.[] | keys] | intersection_of_sorted_arrays

答案 1 :(得分:0)

这里是一个无排序且省时的答案,它依赖于jq在JSON字典中实现查找的效率。由于键是字符串,因此我们可以简单地使用“单词袋”(bow)的概念:

def bow(stream): 
  reduce stream as $word ({}; .[$word|tostring] += 1);

我们现在可以解决“所有对象共有的键”问题,如下所示:

length as $length
| bow(.[] | keys_unsorted[])
| to_entries[]
| select(.value==$length).key

同样,对于“多个对象中的键”问题。

当然,要实现时间效率,需要进行通常的时空权衡。

答案 2 :(得分:0)

或者,可以使用步行路径unix实用程序 jtc 分两步来实现相同的JSON操作:

bash $ <file.json jtc -w'<.*>L:<>k' -j | jtc -w'<.>Q:' -j
[
   "bar",
   "foo"
]
bash $ 
  • 第一步,它列出所有标签(作为JSON数组)
  • 第二步,找到所有重复的记录

PS>披露:我是jtc-用于JSON操作的shell cli工具的创建者