jq:按属性分组和键

问题描述 投票:0回答:4

我有一个看起来像这样的对象列表:

[
  {
    "ip": "1.1.1.1",
    "component": "name1"
  },
  {
    "ip": "1.1.1.2",
    "component": "name1"
  },
  {
    "ip": "1.1.1.3",
    "component": "name2"
  },
  {
    "ip": "1.1.1.4",
    "component": "name2"
  }
]

现在我想按组件对其进行分组和键控,并将 ip 列表分配给每个组件:

{
  "name1": [
    "1.1.1.1",
    "1.1.1.2"
  ]
},{
  "name2": [
    "1.1.1.3",
    "1.1.1.4"
  ]
}
json key grouping jq
4个回答
67
投票

我自己想出来了。我首先按

.component
进行分组,然后创建新的 ip 列表,这些列表由每个组的第一个对象的组件进行索引:

jq ' group_by(.component)[] | {(.[0].component): [.[] | .ip]}'


17
投票

接受的答案不会生成有效的 json,但是:

{
  "name1": [
    "1.1.1.1",
    "1.1.1.2"
  ]
}
{
  "name2": [
    "1.1.1.3",
    "1.1.1.4"
  ]
}

name1
以及
name2
是有效的 json 对象,但整个输出不是。

以下

jq
语句会产生问题中指定的所需输出:

group_by(.component) | map({ key: (.[0].component), value: [.[] | .ip] }) | from_entries

输出:

{
  "name1": [
    "1.1.1.1",
    "1.1.1.2"
  ],
  "name2": [
    "1.1.1.3",
    "1.1.1.4"
  ]
}

欢迎提出更简单方法的建议。

如果人类可读性优于有效的 json,我建议类似......

jq -r 'group_by(.component)[] | "IPs for " + .[0].component + ": " + (map(.ip) | tostring)'

...这导致...

IPs for name1: ["1.1.1.1","1.1.1.2"]
IPs for name2: ["1.1.1.3","1.1.1.4"]

1
投票

作为 @replay 技术的进一步示例,在使用其他方法多次失败后,我最终构建了一个过滤器来压缩此 Wazuh 报告(为简洁起见摘录):

{
  "took" : 228,
  "timed_out" : false,
  "hits" : {
    "total" : {
      "value" : 2806,
      "relation" : "eq"
    },
    "hits" : [
      {
        "_source" : {
          "agent" : {
            "name" : "100360xx"
          },
          "data" : {
            "vulnerability" : {
              "severity" : "High",
              "package" : {
                "condition" : "less than 78.0",
                "name" : "Mozilla Firefox 68.11.0 ESR (x64 en-US)"
              }
            }
          }
        }
      },
      {
        "_source" : {
          "agent" : {
            "name" : "100360xx"
          },
          "data" : {
            "vulnerability" : {
              "severity" : "High",
              "package" : {
                "condition" : "less than 78.0",
                "name" : "Mozilla Firefox 68.11.0 ESR (x64 en-US)"
              }
            }
          }
        }
      },
      ...

这是我用来提供对象数组的

jq
过滤器,每个对象都包含一个代理名称,后跟代理易受攻击的包的名称数组

jq ' .hits.hits |= unique_by(._source.agent.name, ._source.data.vulnerability.package.name) | .hits.hits | group_by(._source.agent.name)[] | { (.[0]._source.agent.name): [.[]._source.data.vulnerability.package | .name ]}'

这里是过滤器产生的输出的摘录:

{
  "100360xx": [
    "Mozilla Firefox 68.11.0 ESR (x64 en-US)",
    "VLC media player",
    "Windows 10"
  ]
}
{
  "WIN-KD5C4xxx": [
    "Windows Server 2019"
  ]
}
{
  "fridxxx": [
    "java-1.8.0-openjdk",
    "kernel",
    "kernel-headers",
    "kernel-tools",
    "kernel-tools-libs",
    "python-perf"
  ]
}
{
  "mcd-xxx-xxx": [
    "dbus",
    "fribidi",
    "gnupg2",
    "graphite2",
    ...

0
投票

作为 yaccob 答案的更简单替代方案,您可以使用

add
运算符将 JSON 对象列表合并为单个对象。

jq '[group_by(.component)[] | {(.[0].component): [.[] | .ip]}] | add'

输出:

{
  "name1": [
    "1.1.1.1",
    "1.1.1.2"
  ],
  "name2": [
    "1.1.1.3",
    "1.1.1.4"
  ]
}
© www.soinside.com 2019 - 2024. All rights reserved.