【问题标题】:jq: group and key by propertyjq:按属性分组和键
【发布时间】:2017-08-30 11:50:18
【问题描述】:

我有一个如下所示的对象列表:

[
  {
    "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"
  }
]

现在我想按组件对其进行分组和键入,并为每个组件分配一个 ips 列表:

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

【问题讨论】:

    标签: json key grouping jq


    【解决方案1】:

    我自己想通了。我首先按.component 分组,然后创建新的ips 列表,这些ips 由每个组的第一个对象的组件索引:

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

    【讨论】:

    • 如果密钥是数字类型怎么办?
    • @branquito 它不能。对象键始终是 JSON 中的字符串。如果你有一个像 {"0": 1} 这样的 JSON,你可以使用 ."0" 获取 "0" 密钥。
    • 此查询产生的输出不是有效的 json。您可以在我最近发布的这个答案中找到进一步的解释:stackoverflow.com/a/69346071/2508466
    【解决方案2】:

    作为@replay's technique的进一步示例,在使用其他方法多次失败后,我终于构建了一个过滤器来浓缩这个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",
        ...
    

    【讨论】:

      【解决方案3】:

      接受的答案不会产生有效的 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"]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-10-07
        • 2022-01-26
        相关资源
        最近更新 更多