当json有多个相同条目时,如何让jq返回唯一结果?

时间:2019-06-17 07:45:05

标签: json unique jq

jq '
  .[]|select(.accountEnabled==true)|select(.assignedPlans[].service=="exchange" and .assignedPlans[].capabilityStatus=="Enabled").proxyAddresses[]'

下面是json的示例,它是匿名的“ az广告用户列表”(从Azure中获取Active Directory用户列表)的输出,并删除了不相关的内容。上面是一个我想用来提取电子邮件地址的jq命令,所需的输出是“ SMTP:russell.coker@example.com”,打印一次而不是9次。是的,我知道我可以将其传递给Unix命令“ sort -u”,但我想对其进行其他json查询。

[
  {
    "accountEnabled": true,
    "assignedPlans": [
      {
        "capabilityStatus": "Enabled",
        "service": "exchange"
      },
      {
        "capabilityStatus": "Enabled",
        "service": "exchange"
      },
      {
        "capabilityStatus": "Enabled",
        "service": "exchange"
      }
    ],
    "provisionedPlans": [
      {
        "capabilityStatus": "Enabled",
        "provisioningStatus": "Success",
        "service": "exchange"
      },
      {
        "capabilityStatus": "Enabled",
        "provisioningStatus": "Success",
        "service": "exchange"
      },
      {
        "capabilityStatus": "Enabled",
        "provisioningStatus": "Success",
        "service": "exchange"
      },
      {
        "capabilityStatus": "Enabled",
        "provisioningStatus": "Success",
        "service": "exchange"
      }
    ],
    "proxyAddresses": [
      "SMTP:russell.coker@example.com"
    ]
  },
  {
    "accountEnabled": true,
    "assignedPlans": [
      {
        "capabilityStatus": "Deleted",
        "service": "exchange"
      },
      {
        "capabilityStatus": "Deleted",
        "service": "OfficeForms"
      }
    ],
    "provisionedPlans": [
      {
        "capabilityStatus": "Deleted",
        "provisioningStatus": "Success",
        "service": "SharePoint"
      },
      {
        "capabilityStatus": "Deleted",
        "provisioningStatus": "Success",
        "service": "exchange"
      },
      {
        "capabilityStatus": "Deleted",
        "provisioningStatus": "Success",
        "service": "exchange"
      }
    ],
    "proxyAddresses": [
      "smtp:a@example.com",
      "smtp:b@example.com",
      "SMTP:c@example.com"
    ]
  }
]

2 个答案:

答案 0 :(得分:1)

  

上面是我要使用的jq命令

以下回复集中在上述要求上。

如果您不介意它对输入进行排序,则可以使用

unique/0。此过滤器需要一个数组作为输入,因此您可以按以下方式修改查询:

[.[]
 | select(.accountEnabled==true)
 | select(.assignedPlans[].service=="exchange" and .assignedPlans[].capabilityStatus=="Enabled")
 | .proxyAddresses[]]
| unique

这会产生一个数组,因此,如果要流,只需在末尾加上[]

一种面向流的方法

在某些情况下,可能希望避免使用sort的{​​{1}}。这是使用通用过滤器unique/0的面向流的解决方案,它不涉及排序,并且具有其他潜在的优点,尽管定义起来有点麻烦,因为它对流没有任何限制。

uniques/1

使用def uniques(stream): foreach stream as $s ({}; ($s|type) as $t | (if $t == "string" then $s else ($s|tostring) end) as $y | if .[$t][$y] then .emit = false else .emit = true | (.item = $s) | (.[$t][$y] = true) end; if .emit then .item else empty end ); ,对前面的解决方案进行小的调整就足够了:

uniques/1

答案 1 :(得分:1)

也许问题在于给定的jq查询只是“错误的”,因为它无法捕获OP的意图。

即使以下查询不能反映OP的意图,值得注意的是,使用给定的JSON,它会生成所需的单个结果:

.[]
| select(.accountEnabled==true)
| select(any(.assignedPlans[];
             .service=="exchange" and
             .capabilityStatus=="Enabled"))
| .proxyAddresses[]

类似....

这是另一个具有不同语义的查询,但是使用给定的JSON也会生成单个所需的结果。 (这表明,单个示例本身不能替代需求。)

.[]
 | select(.accountEnabled==true)
 | select(any(.assignedPlans[]; .service=="exchange"))
 | select(any(.assignedPlans[]; .capabilityStatus=="Enabled"))
 | .proxyAddresses[]