jq: Select 使用 2x 独立级密钥

jq: Select using 2x seperate-level keys

在 JSON 数据上使用 jq ...

我正在尝试 select 在同一记录元素中记录 FromPort 为 80 且 CidrIp 为 0.0.0.0/0 的记录。

这里是查询:

cat data.json |jq -r '.SecurityGroups | .[] | select((.IpPermissions[] | .IpRanges[] | .CidrIp == "0.0.0.0/0") and (.IpPermissions[] | .FromPort == 80))'

数据如下

结果应该只有 select Group3,而不是 selects Group1 和 Group3。我尝试了各种 google 搜索,但仍无法找到答案。

非常感谢任何帮助。

数据(data.json):

{
    "SecurityGroups": [
        {
            "GroupName": "Group1",
            "IpPermissions": [
                {
                    "FromPort": 80,
                    "IpProtocol": "tcp",
                    "IpRanges": [
                        {
                            "CidrIp": "1.2.3.4/24"
                        }
                    ]
                },
                {
                    "FromPort": 6789,
                    "IpProtocol": "tcp",
                    "IpRanges": [
                        {
                            "CidrIp": "1.2.3.4/24"
                        },
                        {
                            "CidrIp": "0.0.0.0/0"
                        }
                    ]
                }
            ]
        },
        {
            "GroupName": "Group2",
            "IpPermissions": [
                {
                    "FromPort": 443,
                    "IpProtocol": "tcp",
                    "IpRanges": [
                        {
                            "CidrIp": "1.2.3.4/24"
                        },
                        {
                            "CidrIp": "0.0.0.0/0"
                        }
                    ]
                },
                {
                    "FromPort": 6788,
                    "IpProtocol": "tcp",
                    "IpRanges": [
                        {
                            "CidrIp": "1.2.3.4/24"
                        }
                    ]
                }
            ]
        },
        {
            "GroupName": "Group3",
            "IpPermissions": [
                {
                    "FromPort": 80,
                    "IpProtocol": "tcp",
                    "IpRanges": [
                        {
                            "CidrIp": "1.2.3.4/24"
                        },
                        {
                            "CidrIp": "0.0.0.0/0"
                        }
                    ]
                },
                {
                    "FromPort": 6789,
                    "IpProtocol": "tcp",
                    "IpRanges": [
                        {
                            "CidrIp": "1.2.3.4/24"
                        }
                    ]
                }
            ]
        }
    ]
}

您选择的迭代 .IpPermissions[] | .IpRanges[] 产生的结果与这些数组中的项目一样多。对于每个 true 结果,您的 select 传递有问题的输入(可能多次)。您需要像 anyall 这样的聚合器将所有结果组合成一个布尔结果,这样 select 就可以传递相应输入的 1 个或 0 个副本。

此外,您在 and 两边 迭代 .IpPermissions[] 在您的条件下,这将产生结果的笛卡尔积。

如果 .IpPermissions 数组中有 至少一个 项目与 .FromPort 并且至少有一个 .IpRanges 数组中的 .CidrIp 匹配:

jq '
  .SecurityGroups[] | select(
    any(.IpPermissions[]; .FromPort == 80 and
      any(.IpRanges[]; .CidrIp == "0.0.0.0/0")
    )
  )
' data.json
{
  "GroupName": "Group3",
  "IpPermissions": [
    {
      "FromPort": 80,
      "IpProtocol": "tcp",
      "IpRanges": [
        {
          "CidrIp": "1.2.3.4/24"
        },
        {
          "CidrIp": "0.0.0.0/0"
        }
      ]
    },
    {
      "FromPort": 6789,
      "IpProtocol": "tcp",
      "IpRanges": [
        {
          "CidrIp": "1.2.3.4/24"
        }
      ]
    }
  ]
}

Demo

你可以适当的使用括号()and来过滤,像这样:(.FromPort==80 and (.IpRanges[] | .CidrIp=="0.0.0.0/0" ))。通过这样做,我们确保两个条件都与IpPermissions.

中的条目匹配

过滤器

.SecurityGroups | map(select(.IpPermissions[] 
| (.FromPort==80 and (.IpRanges[] | .CidrIp=="0.0.0.0/0" ))))

输入

{
  "SecurityGroups": [
    {
      "GroupName": "Group1",
      "IpPermissions": [
        {
          "FromPort": 80,
          "IpProtocol": "tcp",
          "IpRanges": [
            {
              "CidrIp": "1.2.3.4/24"
            }
          ]
        },
        {
          "FromPort": 6789,
          "IpProtocol": "tcp",
          "IpRanges": [
            {
              "CidrIp": "1.2.3.4/24"
            },
            {
              "CidrIp": "0.0.0.0/0"
            }
          ]
        }
      ]
    },
    {
      "GroupName": "Group2",
      "IpPermissions": [
        {
          "FromPort": 443,
          "IpProtocol": "tcp",
          "IpRanges": [
            {
              "CidrIp": "1.2.3.4/24"
            },
            {
              "CidrIp": "0.0.0.0/0"
            }
          ]
        },
        {
          "FromPort": 6788,
          "IpProtocol": "tcp",
          "IpRanges": [
            {
              "CidrIp": "1.2.3.4/24"
            }
          ]
        }
      ]
    },
    {
      "GroupName": "Group3",
      "IpPermissions": [
        {
          "FromPort": 80,
          "IpProtocol": "tcp",
          "IpRanges": [
            {
              "CidrIp": "1.2.3.4/24"
            },
            {
              "CidrIp": "0.0.0.0/0"
            }
          ]
        },
        {
          "FromPort": 6789,
          "IpProtocol": "tcp",
          "IpRanges": [
            {
              "CidrIp": "1.2.3.4/24"
            }
          ]
        }
      ]
    }
  ]
}

输出

[
  {
    "GroupName": "Group3",
    "IpPermissions": [
      {
        "FromPort": 80,
        "IpProtocol": "tcp",
        "IpRanges": [
          {
            "CidrIp": "1.2.3.4/24"
          },
          {
            "CidrIp": "0.0.0.0/0"
          }
        ]
      },
      {
        "FromPort": 6789,
        "IpProtocol": "tcp",
        "IpRanges": [
          {
            "CidrIp": "1.2.3.4/24"
          }
        ]
      }
    ]
  }
]

现在只能看到输出了Group3

演示

https://jqplay.org/s/qZvARp_5LE

或者您可以按照 pmf 的建议使用 any/2

过滤器

.SecurityGroups[] 
| select(any(.IpPermissions[]; .FromPort==80 
and any(.IpRanges[]; .CidrIp=="0.0.0.0/0")))

演示

https://jqplay.org/s/Rw2_dtzwUA