【问题标题】:How to join json files using jq?如何使用 jq 加入 json 文件?
【发布时间】:2020-02-05 16:53:07
【问题描述】:

我有以下 json 文件

[
  {
    "clusterName": "cluster1",
    "nodes": [
      {
        "hostname": "server1",
        "dse": "6.7.5"
      },
      {
        "hostname": "server2",
        "dse": "6.7.5"
      }
    ]
  },
  {
    "clusterName": "cluster2",
    "nodes": [
      {
        "hostname": "server3",
        "dse": "6.7.5"
      },
      {
        "hostname": "server4",
        "dse": "6.7.5"
      }
    ]
  }
]

我还有另一个 json

[
  {
    "hostname": "server1",
    "memorysize": "47.01 GiB",
    "processorcount": 12
  },
  {
    "hostname": "server2",
    "memorysize": "47.01 GiB",
    "processorcount": 12
  },
  {
    "hostname": "server3",
    "memorysize": "47.01 GiB",
    "processorcount": 10
  },
  {
    "hostname": "server4",
    "memorysize": "47.01 GiB",
    "processorcount": 11
  },
  {
    "hostname": "server5",
    "memorysize": "47.01 GiB",
    "processorcount": 12
  },
  {
    "hostname": "server6",
    "memorysize": "47.01 GiB",
    "processorcount": 12
  }
]

我想加入这两个 json 以产生以下输出

[
  {
    "clusterName": "cluster1",
    "nodes": [
      {
        "hostname": "server1",
        "dse": "6.7.5",
        "memorysize": "47.01 GiB",
        "processorcount": 12
      },
      {
        "hostname": "server2",
        "dse": "6.7.5",
        "memorysize": "47.01 GiB",
        "processorcount": 12
      }
    ]
  },
  {
    "clusterName": "cluster2",
    "nodes": [
      {
        "hostname": "server3",
        "dse": "6.7.5",
        "memorysize": "47.01 GiB",
        "processorcount": 10
      },
      {
        "hostname": "server4",
        "dse": "6.7.5",
        "memorysize": "47.01 GiB",
        "processorcount": 11
      }
    ]
  }
]

基本上第一个文件有集群字典列表。有节点,我有第二个文件,其中包含节点字典列表。

提到的解决方案不适用于多个集群。

有没有更好的方式在 python 中执行此操作?

【问题讨论】:

  • 我们可以假设第一个文件的每个节点在第二个文件中都会有一个关联的对象吗?
  • @Aaron 第一个文件的每个节点都会在第二个文件中有一个关联的对象。
  • 我的 jq foo 很弱,所以我不确定如何最好地合并它,但是您可以使用 cat file1.txt file2.txt | jq -s ".[0][].nodes[] * .[1][0]" 获得所需的节点数组
  • 我相信您在问题的第三个代码 sn-p 中有错字 - 您想要的输出。外部数组有两个元素,其中第二个元素的键为"clusterName",值为"cluster2"。第二个元素的"nodes" 数组又具有两个元素,其中第一个元素的"hostname" 设置为"server3"。但是第二个元素应该将其"hostname" 设置为"server4"。对? - 我建议您考虑更正这一点,以免混淆任何来到这里的读者。 (由于“6 个字符规则”,我无法自己编辑。)
  • 感谢您发现错字。我已经更新了。

标签: json linux jq


【解决方案1】:

使用jq的解决方案:

<file1 jq --slurpfile f file2 '
  {
     clusterName:.[].clusterName,
     nodes:map($f[],.nodes)|add|group_by(.hostname)|map(add)
  }'

这会使用这两个文件构建一个对象。
第一个字段clusterName 取自第二个文件的同一字段。
第二个字段nodes是基于hostname的两个对象的组合(使用group_by命令完成)


对以下评论的初步回答:
我不认为 -s 在这里有任何优势,因为您需要内存中的两个文件(而不是 1 和 --slurpfile)。
为了不使用索引,我们的想法是在使用之前测试该字段是否存在。您可以使用 ?// 运算符来执行此操作。他们一起来自if not ... then ...。 这是一个可能的解决方案:

jq -s '{
   clusterName:(.[][].clusterName?//empty),
   nodes:map(.[].nodes[]?//.[])|group_by(.hostname)|map(add)
}' file1 file2

如您所见,两个脚本的难点在于“规范化”对象以执行group_by 操作。

【讨论】:

  • 与其写入文件,我更希望看到更简洁的实现:jq --slurp '{ clusterName: .[0][].clusterName, nodes: [[.[1][]], .[0][0].nodes] | add | group_by(.hostname) | map(add) }' file1.txt file2.txt 提出一个新问题很诱人!您将如何使用 --slurp 而不是 --slurpfile 来实现此解决方案?
  • 太棒了!谢谢。对我来说,--slurp 的最大优势是我经常使用jq 作为过滤器,其中两个对象都不在文件中,jq 只是从流中读取。
  • 也就是说,调用看起来更像cat file1 file2 | jq -s ...,而不是jq -s ... file1 file2(其中cat被一些非平凡的json对象生成器替换)
  • 相同条件下,我经常使用json_producer1 | jq --slurpfile f &lt;(json_producer2) '...'
  • 我已经更新了问题描述,因为多个集群的建议都失败了。
【解决方案2】:

我用 python 代替了这个

for cluster in clusters:
    for node in cluster["nodes"]:
        node.update(list(filter(lambda nodes: nodes['hostname'] == node['hostname'],nodes))[0])

【讨论】:

    【解决方案3】:

    调用看起来更像 cat file1 file2 | jq ...

    这是一个假设所有输入都以流的形式呈现的解决方案。此解决方案还避免使用 -s 命令行选项。

    cat master.json hostnames.json | jq '
      # input: an array of objects, each with a "nodes" key
      def mergeNode($node): 
        map(if .hostname == $node.hostname then . + $node else . end);
      reduce inputs[] as $n (.; map_values( .nodes |= mergeNode($n) ))'
    

    请注意,尚未指定 -n 命令行选项。

    此解决方案还允许多个“主机名”文件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-16
      • 1970-01-01
      • 2019-06-11
      • 2019-01-27
      • 1970-01-01
      • 2019-08-31
      • 2019-12-01
      相关资源
      最近更新 更多