首页 > 解决方案 > jq - 从文件中合并任意数量的 json 数组时列表中的重复对象

问题描述

我正在使用 saltstack 配置 cloudwatch 代理日志(这就是为什么会有一些奇怪的语法)。我正在尝试将任意数量的包含相同架构但不同数据的文件合并到一个文件中。

文件 1

{
  "logs": {
    "logs_collected": {
      "files":{
        "collect_list": [
          {
            "file_name": "/var/log/suricata/eve-ips.json",
            "log_group_name": "{{grains.environment_full}}SuricataIPS",
            "log_stream_name": "{{grains.id}}",
            "timezone": "UTC",
            "timestamp_format": "%Y-%m-%dT%H:%M:%S.%f+0000"
          }
        ]
      }
    }
  }
}

文件 2

{
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_name": "/var/log/company/company-json.log",
            "log_group_name": "{{grains.environment_full}}Play",
            "log_stream_name": "{{grains.id}}",
            "timezone": "UTC",
            "timestamp_format": "%Y-%m-%dT%H:%M:%S.%fZ"
          },
          {
            "file_name": "/var/log/company/company-notifications.log",
            "log_group_name": "{{grains.environment_full}}Notifications",
            "log_stream_name": "{{grains.id}}",
            "timezone": "UTC",
            "timestamp_format": "%Y-%m-%dT%H:%M:%S.%fZ"
          }
        ]
      }
    }
  }
}

文件 3

{
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_name": "/var/ossec/logs/alerts/alerts.json",
            "log_group_name": "{{grains.environment_full}}OSSEC",
            "log_stream_name": "{{grains.id}}",
            "timezone": "UTC",
            "timestamp_format": "%Y-%m-%d %H:%M:%S"
          }
        ]
      }
    }
  }
}

jq 查询(基于一些 SO 帮助)

jq  -s '.[0].logs.logs_collected.files.collect_list += [.[].logs.logs_collected.files.collect_list | add] | unique| .[0]' web.json suricata.json wazuh-agent.json

输出

{
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_name": "/var/log/company/company-json.log",
            "log_group_name": "{{grains.environment_full}}Play",
            "log_stream_name": "{{grains.id}}",
            "timezone": "UTC",
            "timestamp_format": "%Y-%m-%dT%H:%M:%S.%fZ"
          },
          {
            "file_name": "/var/log/company/company-notifications.log",
            "log_group_name": "{{grains.environment_full}}Notifications",
            "log_stream_name": "{{grains.id}}",
            "timezone": "UTC",
            "timestamp_format": "%Y-%m-%dT%H:%M:%S.%fZ"
          },
          {
            "file_name": "/var/log/company/company-notifications.log",
            "log_group_name": "{{grains.environment_full}}Notifications",
            "log_stream_name": "{{grains.id}}",
            "timezone": "UTC",
            "timestamp_format": "%Y-%m-%dT%H:%M:%S.%fZ"
          },
          {
            "file_name": "/var/log/suricata/eve-ips.json",
            "log_group_name": "{{grains.environment_full}}SuricataIPS",
            "log_stream_name": "{{grains.id}}",
            "timezone": "UTC",
            "timestamp_format": "%Y-%m-%dT%H:%M:%S.%f+0000"
          },
          {
            "file_name": "/var/ossec/logs/alerts/alerts.json",
            "log_group_name": "{{grains['environment_full']}}OSSEC",
            "log_stream_name": "{{grains.id}}",
            "timezone": "UTC",
            "timestamp_format": "%Y-%m-%d %H:%M:%S"
          }
        ]
      }
    }
  }
}

如果你已经走到这一步,谢谢你。另外需要注意的一点是,如果我更改文件的顺序,则第一个索引collect_list总是重复的,如果web.json是最后一个(唯一一个长度为 2),则第二个日志文件不在组中。

标签: jq

解决方案


作为您所做尝试的一部分,您有几个不正确的步骤。首先,转换所有“列表”数组的数组

[.[].logs.logs_collected.files.collect_list] 

对于单个数组,您需要使用add,但调用它的方式不正确。add 将输入作为对象数组,并将数组的元素加在一起作为输出。所以应该是

[.[].logs.logs_collected.files.collect_list] | add

接下来是unique函数,它再次将一个数组作为输入,并按排序顺序生成一个相同元素的数组,并删除重复项。

[.[].logs.logs_collected.files.collect_list] | add | unique

至于第一个元素的重复,这是因为您使用的是 append 操作+=而不是 assignment =。因为运算符右侧的代码将来自所有对象的条目分组,所以使用追加仅将第一个对象中的值与其余对象组合在一起。

在从结果对象(..)访问 之前,还将这些函数分组在一起。.[0]因此,无论文件的顺序如何,将它们放在一起都会按预期工作。

jq -s '.[0].logs.logs_collected.files.collect_list = ([.[].logs.logs_collected.files.collect_list]|add|unique)|.[0]' 

另一个变体使用reduce无需使用slurp模式-s,而是处理inputs标准输入上所有可用文件的 ie 内容

jq -n 'reduce inputs.logs.logs_collected.files.collect_list as $d (.; .logs.logs_collected.files.collect_list += $d)'

推荐阅读