【问题标题】:Filtering JSON object list with jq by matching multiple objects通过匹配多个对象,用 jq 过滤 JSON 对象列表
【发布时间】:2016-03-02 15:01:09
【问题描述】:

我正在尝试过滤“aws elb describe-tags”的输出,并通过匹配三个标签来获取 LoadBalancerName。我没有看到如何选择对象列表的特定元素并比较键和值。我要查看三个对象,如果它们都匹配,我需要返回 LoadBalancerName。

这是三个负载均衡器的示例输出,其中只有一个具有正确的标签集。

{
    "TagDescriptions": [
        {
            "Tags": [
                {
                    "Value": "production",
                    "Key": "environment"
                },
                {
                    "Value": "widget",
                    "Key": "service"
                },
                {
                    "Value": "widget_xyz",
                    "Key": "customer_prefix"
                },
                {
                    "Value": "widget_xyz-widget-production",
                    "Key": "Name"
                }
            ],
            "LoadBalancerName": "widget-xyz-widget-prod"
        },
        {
            "Tags": [
                {
                    "Value": "widget-xyz-stage-widget-ConsulStack-DKJSADKJS",
                    "Key": "aws:cloudformation:stack-name"
                },
                {
                    "Value": "stage",
                    "Key": "environment"
                },
                {
                    "Value": "arn:aws:cloudformation:us-east-1:123456789:stack/widget-xyz-stage-widget-ConsulStack-DKJSADKJS/d46ad520-92e7-11e5-a975-500150b34c7c",
                    "Key": "aws:cloudformation:stack-id"
                },
                {
                    "Value": "widget",
                    "Key": "service"
                },
                {
                    "Value": "widget_xyz",
                    "Key": "customer_prefix"
                },
                {
                    "Value": "ELB",
                    "Key": "aws:cloudformation:logical-id"
                },
                {
                    "Value": "widget_xyz-widget-stage",
                    "Key": "Name"
                }
            ],
            "LoadBalancerName": "widget-xyz-ELB-SDKJSDKJSADKJAS"
        },
        {
            "Tags": [
                {
                    "Value": "widget-xyz-prod-widget-ConsulStack-DLFJEIJNWDKD",
                    "Key": "aws:cloudformation:stack-name"
                },
                {
                    "Value": "prod",
                    "Key": "environment"
                },
                {
                    "Value": "arn:aws:cloudformation:us-east-1:123456789:stack/widget-xyz-prod-widget-ConsulStack-DLFJEIJNWDKD/ab2292f0-9398-11e5-b0f6-50d501114c2c",
                    "Key": "aws:cloudformation:stack-id"
                },
                {
                    "Value": "widget",
                    "Key": "service"
                },
                {
                    "Value": "widget_xyz",
                    "Key": "customer_prefix"
                },
                {
                    "Value": "ELB",
                    "Key": "aws:cloudformation:logical-id"
                },
                {
                    "Value": "widget_xyz-widget-prod",
                    "Key": "Name"
                }
            ],
            "LoadBalancerName": "widget-xyz-ELB-SKDJSKDJSAKDJAS"
        }
    ]
}

我已成功实施我的查询,但不安全。只要任何三个值与我的搜索模式匹配,它就会返回 LoadBalancerName。我想搜索一个特定的Key,然后比较Value。

这是我的不安全查询,它在要点的摘要上成功。它返回 widget-xyz-widget-prod,这是我要获取的参数。

jq --raw-output '.TagDescriptions[] | select(.Tags[].Value=="widget_xyz") | select(.Tags[].Value=="widget") | select(.Tags[].Value=="production") | .LoadBalancerName'

如果所有三个条件都为真,它应该返回:

Key == "service" && Value == "widget"
Key == "environment" && Value == "production"
Key == "customer_prefix" && Value == "widget_xyz"

正如您在上面的查询中看到的,我只是在比较值。

更新:我已经能够构建一个查询来过滤匹配来自一个对象的键和值,但我仍在尝试匹配多个对象。

.TagDescriptions[] | select(.Tags[].Key=="customer_prefix" and .Tags[].Value == "widget_xyz") | .LoadBalancerName

另一个更新:好的,所以,我已经能够一起破解一个查询。我觉得好像我还缺少一块拼图,并且可以使用 jq 的一些我尚未理解的巧妙功能大大简化此查询。

.TagDescriptions[] | [select(.Tags[].Key == "customer_prefix" and .Tags[].Value == "widget_xyz")][] | [select(.Tags[].Key == "environment" and .Tags[].Value == "production")][] | [select(.Tags[].Key == "service" and .Tags[].Value == "widget")][] | .LoadBalancerName

【问题讨论】:

  • 嗨,布莱恩!你能添加一个预期输出的例子吗?
  • 嗨圣地亚哥!我已经编辑了我的问题以包含更完整的 json 代码段。我希望能更好地解释我的问题。我有一个有效的查询,但它不安全。我希望改进此查询以确保特定键具有特定值。现在只要任何三个值与我的三个约束匹配,我的查询就会返回。

标签: json jq


【解决方案1】:

Tags 数组非常适合创建对象以便于访问。让自己轻松一些,并这样做。然后访问这些值会容易得多。然后您可以轻松测试,看看您的条件是否满足。

.TagDescriptions[] | select(
    .Tags | from_entries | [
        .service == "widget",
        .environment == "production",
        .customer_prefix == "widget_xyz"
    ] | all
).LoadBalancerName

【讨论】:

  • 谢谢 - 我真的很喜欢这种方法。
【解决方案2】:

给 jq 猫剥皮的方法不止一种,但主要的关键之一是 获得清晰的解决方案是定义助手的能力 函数,实际上可以嵌套。无论如何,这是一个使用具有内部函数的辅助函数的解决方案。

# Does "obj" match any of the objects in the input array?
def anymatch(obj):
  # Do all the key-value pairs in obj also occur in the input?
  def match(obj):
    . as $in
    | obj as $o
    | all( $o|keys[]; $in[.] == $o[.]);
  any(.[]; match(obj));

.TagDescriptions[]
| select( .Tags
        | (anymatch({"Key":"customer_prefix", "Value": "widget_xyz"})
           and anymatch({"Key":"environment", "Value": "production"})
           and anymatch({"Key":"service", "Value": "widget"} ) ))
| .LoadBalancerName

对于给定的输入,这会产生: "widget-xyz-widget-prod"

(顺便说一句,我认为您的“另一个更新”解决方案不是解决所述问题的有效解决方案,至少据我了解。)

【讨论】:

  • 谢谢。关于“另一个更新”中所述的解决方案,您能分享一下您看到的错误吗?
  • 尝试在“widget-xyz-widget-prod”块的 .Tags 中交换一对值。
猜你喜欢
  • 1970-01-01
  • 2017-06-14
  • 1970-01-01
  • 2018-01-17
  • 1970-01-01
  • 2012-09-09
  • 2021-12-05
  • 2015-03-24
  • 1970-01-01
相关资源
最近更新 更多