如何使用 jq 对 json 进行分组,然后转换为 yaml

how to group json using jq and then convert to yaml

我有这个 json 我想转换。

[
  {
    "externalGroup": "another group admins",
    "groupId": "da2e42c8-6423-4d32-99b5-5fc58f9f80b8"
  },
  {
    "externalGroup": "another group users",
    "groupId": "7c69cac1-4a70-4170-8251-cde3762fe498"
  },
  {
    "externalGroup": "my group admin",
    "groupId": "e08a1d9d-f108-4e87-bdb3-ee4f10c6752a"
  },
  {
    "externalGroup": "my group users",
    "groupId": "8370821e-edfa-4615-ac2e-47815b740f40"
  },
  {
    "externalGroup": "some group",
    "groupId": "e08a1d9d-f108-4e87-bdb3-ee4f10c6752a"
  },
  {
    "externalGroup": "some group",
    "groupId": "8370821e-edfa-4615-ac2e-47815b740f40"
  },
  {
    "externalGroup": "some group",
    "groupId": "7c69cac1-4a70-4170-8251-cde3762fe498"
  }
]

我试过这个,非常接近: jq '. | group_by(.externalGroup)[] | {(.[0].externalGroup): map(.groupId)}'

我明白了:

{
  "another group admins": [
    "da2e42c8-6423-4d32-99b5-5fc58f9f80b8"
  ]
}
{
  "another group users": [
    "7c69cac1-4a70-4170-8251-cde3762fe498"
  ]
}
{
  "my group admin": [
    "e08a1d9d-f108-4e87-bdb3-ee4f10c6752a"
  ]
}
{
  "my group users": [
    "8370821e-edfa-4615-ac2e-47815b740f40"
  ]
}
{
  "some group": [
    "e08a1d9d-f108-4e87-bdb3-ee4f10c6752a",
    "8370821e-edfa-4615-ac2e-47815b740f40",
    "7c69cac1-4a70-4170-8251-cde3762fe498"
  ]
}

但这不能正确转换为 yq。它需要看起来像这样:

{
  "another group admins": [
    "da2e42c8-6423-4d32-99b5-5fc58f9f80b8"
  ],
  "another group users": [
    "7c69cac1-4a70-4170-8251-cde3762fe498"
  ],
  "my group admin": [
    "e08a1d9d-f108-4e87-bdb3-ee4f10c6752a"
  ],
  "my group users": [
    "8370821e-edfa-4615-ac2e-47815b740f40"
  ],
  "some group": [
    "e08a1d9d-f108-4e87-bdb3-ee4f10c6752a",
    "8370821e-edfa-4615-ac2e-47815b740f40",
    "7c69cac1-4a70-4170-8251-cde3762fe498"
  ]
}

为了得到类似的东西:

"another group admins":
  - "da2e42c8-6423-4d32-99b5-5fc58f9f80b8"
"another group users":
  - "7c69cac1-4a70-4170-8251-cde3762fe498"
"my group admin":
  - "e08a1d9d-f108-4e87-bdb3-ee4f10c6752a"
"my group users":
  - "8370821e-edfa-4615-ac2e-47815b740f40"
"some group":
  - "e08a1d9d-f108-4e87-bdb3-ee4f10c6752a",
  - "8370821e-edfa-4615-ac2e-47815b740f40",
  - "7c69cac1-4a70-4170-8251-cde3762fe498"

您缺少的部分是 from_entries,它可以从键和值数组构建 JSON 对象。

而不是:

jq '. | group_by(.externalGroup)[] | {(.[0].externalGroup): map(.groupId)}'

尝试:

jq 'group_by(.externalGroup) | map({key:.[0].externalGroup, value:map(.groupId)}) | from_entries'
{
  "another group admins": [
    "da2e42c8-6423-4d32-99b5-5fc58f9f80b8"
  ],
  "another group users": [
    "7c69cac1-4a70-4170-8251-cde3762fe498"
  ],
  "my group admin": [
    "e08a1d9d-f108-4e87-bdb3-ee4f10c6752a"
  ],
  "my group users": [
    "8370821e-edfa-4615-ac2e-47815b740f40"
  ],
  "some group": [
    "e08a1d9d-f108-4e87-bdb3-ee4f10c6752a",
    "8370821e-edfa-4615-ac2e-47815b740f40",
    "7c69cac1-4a70-4170-8251-cde3762fe498"
  ]
}

我做了以下修改:

  • 删除了开头的 . |,因为它没有任何改变。
  • 删除了 [] 并改用 map(...),因为我们希望将内容保存在数组中以提供给 from_entries
  • 我们创建 {key:..., value:...} 对以提供给 from_entries
  • ,而不是组装单条目对象

实际上,我刚刚检查了一下,发现 add 实际上比 from_entries 快一点,即使对于很长的列表也是如此。如果您使用 add,您需要更改更少的解决方案。

jq 'group_by(.externalGroup) | map({(.[0].externalGroup):map(.groupId)}) | add'

将对象加在一起会将它们的内容组合在一起。我用 250,000 个元素的列表进行测试,它比 from_entries 稍微快一点。鉴于它也更短,而且在我看来也同样清晰,我认为它值得考虑。

  1. 一个值得考虑的用于生成 yaml 的替代方案是 gojq,jq 的 Go 实现,例如
   gojq --yaml-output '
     group_by(.externalGroup) 
    | map({(.[0].externalGroup):map(.groupId)}) | add'
  1. 为了避免 map 的开销,您可以使用以下通用的面向流的 add,它适用于对象或数组以及数字:
    gojq --yaml-output '
      def add(s): reduce s as $x (null; . + $x);
      add( group_by(.externalGroup)[] 
           | {(.[0].externalGroup):map(.groupId)})'