【问题标题】:Intersecting nested JSON documents with jq将嵌套的 JSON 文档与 jq 相交
【发布时间】:2021-12-06 09:53:58
【问题描述】:

我正在寻找一种使两个嵌套 JSON 对象相交的通用方法,以便检索所有常见的键值对。

鉴于以下 JSON 文档

{
    "a": 0,
    "b": [
      "ba",
      {
        "bb": {
          "bba": "a",
          "bbc": [1, 2]
        }
      },
      {
        "bc": {
          "bca": [2],
          "bcb": 5
        }
      }
    ],
    "c": 1
  }

和

 {
    "a": 1,
    "b": [
      "ba",
      {
        "bb": {
          "bba": "a",
          "bbc": [1,3]
        }
      }
    ], 
    "c": 1
  }

我想找到他们的交点。 我希望得到以下 JSON 文档,其中仅包含两个输入中都存在的键值对 JSON 对象:

 {
    "b": [
      "ba",
      {
        "bb": {
          "bba": "a",
          "bbc": [1]
        }
      }
    ], 
    "c": 1
  }

我查看了 jq 的文档,但找不到有关如何执行此操作的提示。 我尝试使用减号运算符没有成功,产生object ... and object cannot be subtracted。

 cat obj-list.txt | jq -c '.[1] - (.[0] - .[1])'

你能给我一些关于如何用 jq 完成嵌套 JSON 对象的交集的提示吗?

提前感谢您帮助我。

更新: 鉴于 JSON 对象不具有完全相同的结构,但不同,例如 a = {"a": [{"aa":1]}, b = {"a": 0}。我对如何添加错误检查以捕获 Cannot index number with string-errors 等的解决方案感兴趣?

【问题讨论】:

  • 不是你的问题的一部分,但顺便说一句:总是更喜欢jq ... <obj-list.txt或jq ... obj-list.txt或<obj-list.txt jq ...而不是cat obj-list.txt | jq ...。特别是对于 jq 来说,这并不是什么大问题,但它实际上是其他命令(tail.wc -c 等)的 O(1) 和 O(n) 操作之间的差异,并且对于其他命令(f /e, sort 可以使用真实的文件句柄并行化其操作,但不能使用来自cat 的管道,因为多个线程或子进程只能使用可搜索的文件句柄并行读取输入)。
  • 感谢您提醒我UUOC!没想到这里。 :)

标签: json jq


【解决方案1】:

假设 $a 包含您的一个 JSON 实体的内容,而 $b 包含另一个,那么以下将执行您描述的交集类型:

reduce ($a|paths) as $p (null;
  ($a|getpath($p)) as $va
  | [try ($b|getpath($p)) // empty] as $vb
  | if ($vb | length > 0) and ($va == $vb[0])
    then setpath($p;$va) else . end)

不过,您可能希望探索其变体,例如如果没有共同点。


脚注 1:

以上内容很容易适应类似的问题。例如,如果通用结构是最重要的:

def structural_intersection($a;$b):
  reduce ($a|paths|select(.[-1]|type=="string")) as $p (null;
  ($a|getpath($p)) as $va
  | [try ($b|getpath($p)) // empty] as $vb
  | if ($vb | length > 0) 
    then setpath($p;null) else . end) ;

脚注 2: 要使用数组交集处理数组,您可能希望考虑以下事项,但请注意,在某些情况下,这种混合方法可能会产生您可能意想不到的结果:

def special_intersection($a;$b):
  def i(x;y): x - (x-y);
  reduce ($a|paths) as $p (null;
    ($a|getpath($p)) as $va
    | [try ($b|getpath($p)) // empty] as $vb
    | if ($vb | length > 0)
      then if ($va == $vb[0])
           then setpath($p;$va)
           elif ($va|type == "array") and ($vb[0]|type) == "array"
           then setpath($p; i($va; $vb[0]))
           else . end
      else . end) ;

【讨论】:

  • 我还有一个问题:鉴于 JSON 实体不具有完全相同的结构,但不同,例如 a = {"a": [{"aa":1]}, b = {"a": 0}。如何添加错误检查以捕获 Cannot index number with string-errors 等?提前致谢!
  • @Jeremy - 请查看更新。
  • 非常感谢您的热心回复!非常感谢!
  • 不幸的是,我还有一个问题,我无法自己解决。给定a = {"a": 0, "b": [["bb"], {"bb": 1}],"c": 1} 和b = {"a": 0, "b": [["aa", "bb"], {"bb": 1}], "c": 1},我如何遍历数组值? ["bb"] 不匹配。 @peak 你有什么提示吗?提前致谢。
  • @Jeremy - 见脚注 2。
猜你喜欢
  • 2022-01-13
  • 1970-01-01
  • 2019-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多