使用jq通过搜索子键/值对来选择父项

时间:2016-10-11 06:09:00

标签: json bash select jq

使用jq,如果父对象包含满足两个过滤器要求的子对象,如何选择它?

在这个例子中,我想选择所有子网元素,这些子网元素的子标记键为“Name”,值为“TheName”。我的例子有两个子网。第一个在错误的键中有“TheName”。第二个子网具有我要查找的名称/值对。即"Key": "Name", "Value": "TheName"

以下选择其中一个标记中具有指定值的子网,但不选择该对。它返回两个子网而不是仅返回第二个子网。

jq '.Subnets[] | select(.Tags[].Value=="TheName")' output

如何使用jq仅选择具有我正在寻找的名称/值对的子网?

{
    "Subnets": [
        {
            "VpcId": "vpc-12345678",
            "SubnetId": "subnet-1234567a",
            "Tags": [
                {
                    "Key": "IgnoreThis",
                    "Value": "TheName"
                },
                {
                    "Key": "Name",
                    "Value": "NotTheName"
                }
            ]
        },
        {
            "VpcId": "vpc-12345678",
            "SubnetId": "subnet-1234567b",
            "Tags": [
                {
                    "Key": "IgnoreThis",
                    "Value": "ignore"
                },
                {
                    "Key": "Name",
                    "Value": "TheName"
                }
            ]
        }
    ]
}

所需的输出是:

{
    "VpcId": "vpc-12345678",
    "SubnetId": "subnet-1234567b",
    "Tags": [
        {
            "Key": "IgnoreThis",
            "Value": "ignore"
        },
        {
            "Key": "Name",
            "Value": "TheName"
        }
    ]
}

2 个答案:

答案 0 :(得分:8)

假设你的jq有any/2,一个简单而有效的解决方案是:

.Subnets[]
| select( any (.Tags[]; .Key == "Name" and .Value == "TheName") )

这会产生你想要的输出,所以我不会在这里重复。

如果您的jq没有any/2,我建议升级,但如果这不方便或不是选项,您可以使用此def:

def any(f;g): reduce f as $i (false; . or ($i|g));

P.S。 any(str; cond)可以理解为:'流中是否有任何元素e,str,e|cond的值不是nullfalse?< / p>

答案 1 :(得分:0)

以下是使用indices

的解决方案
.Subnets[] | select(.Tags | indices({Key:"Name", Value:"TheName"}) != [])