jq - 基于现有对象创建新对象

jq - create new object based on existing objects

第一次post,如有不完善之处还请见谅

我有 json 如下所示。它由两部分组成。第一部分包含有关用户的信息(id、全名和电子邮件),第二部分包含用户所属团队的信息。 (id, 团队, 角色) 我想要得到的对象包含:id、fullName、emaila、team 和 role。我可以做到,但只有当用户属于一个团队时。如果用户属于多个团队 - 我无法处理。

下面我的json:

[
  {
    "id": "user1",
    "fullName": "User One",
    "email": "user.one@my.mail.com"
  },
  {
    "id": "user2",
    "fullName": "User Two",
    "email": "user.two@my.mail.com"
  },
  {
    "id": "user1",
    "team": "Team_A",
    "role": "TEAM_MEMBER"
  },
  {
    "id": "user1",
    "team": "Team_B",
    "role": "TEAM_ADMIN"
  },
  {
    "id": "user2",
    "team": "Team_B",
    "role": "TEAM_ADMIN"
  }
]

当我使用:group_by(.id)[] | add 我得到:

{
  "id": "user1",
  "fullName": "User One",
  "email": "user.one@my.mail.com",
  "team": "Team_B",
  "role": "TEAM_ADMIN"
},
{
  "id": "user2",
  "fullName": "User Two",
  "email": "user.two@my.mail.com",
  "team": "Team_B",
  "role": "TEAM_ADMIN"
}

这几乎就是我想要实现的。我的目标是:

{
  "id": "user1",
  "fullName": "User One",
  "email": "user.one@my.mail.com",
  "team": "Team_A,
  "role": "TEAM_MEMBER"
},
{
  "id": "user1",
  "fullName": "User One",
  "email": "user.one@my.mail.com",
  "team": "Team_B",
  "role": "TEAM_ADMIN"
},
{
  "id": "user2",
  "fullName": "User Two",
  "email": "user.two@my.mail.com",
  "team": "Team_B",
  "role": "TEAM_ADMIN"
}

我也试过 reduce,但没有成功。 我做了很多尝试,但是 none 次尝试达到了预期的效果。

如何使用 jq

提前致谢,

克日洪

您似乎收集了一些关于用户的信息。您不能通过合并具有相同 id 的所有内容来压平它们,它们需要分开。

您有“用户信息”(全名和电子邮件)和“团队信息”。您需要按id分组,然后按类型分组,然后分发“用户信息”。

这是您可以采用的一种方法。

# partition the data by "user/team type"
reduce .[] as $i ({}; if "fullName" | in($i) then .user += [$i] else .team += [$i] end)

  # create a lookup of "user" data
  | (.user | INDEX(.id)) as $user

  # group the "team" objects by team
  | .team | group_by(.team)

  # merge corresponding "user info" with all team objects
  | map(map(. + $user[.id]))
[
  [
    {
      "id": "user1",
      "team": "Team_A",
      "role": "TEAM_MEMBER",
      "fullName": "User One",
      "email": "user.one@my.mail.com"
    }
  ],
  [
    {
      "id": "user1",
      "team": "Team_B",
      "role": "TEAM_ADMIN",
      "fullName": "User One",
      "email": "user.one@my.mail.com"
    },
    {
      "id": "user2",
      "team": "Team_B",
      "role": "TEAM_ADMIN",
      "fullName": "User Two",
      "email": "user.two@my.mail.com"
    }
  ]
]

jqplay


这是另一个更简洁的解决方案,假设每个 id 只有一个“用户信息”。

# group by id
group_by(.id) | map(
    # for each group, partition by "type"
    group_by(.fullName)

      # create combinations of all the info and team objects and merge them
      | combinations | add
)

jqplay

这个解决方案使用了一种基于combinations的@JeffMercado 方法的变体,但只使用了一次group_by(这意味着对于大型数据集,它应该更有效,因为group_by 是一个相对昂贵的操作)。

此处建议的解决方案生成一个包含您指定的 JSON 个对象的数组,但如果您想要 JSON 个对象的流,只需省略外部方括号即可。

[group_by(.id)[]
 | [map(select(has("team")|not)), map(select(has("team")))]
 | combinations
 | add]

效率更高...

为了完全避免使用 group_byselect,我们可以使用 group_by 的以下通用变体:

def aggregate_by(s; f):
  reduce s as $x (null; .[$x|f] += [$x]);

解决方案现在可以写成如下:

[ aggregate_by(.[]; .id)[]
  | aggregate_by(.[]; .team == null | tostring)
  | [.[]]
  | combinations
  | add ]