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"
}
]
]
这是另一个更简洁的解决方案,假设每个 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
)
这个解决方案使用了一种基于combinations
的@JeffMercado 方法的变体,但只使用了一次group_by
(这意味着对于大型数据集,它应该更有效,因为group_by
是一个相对昂贵的操作)。
此处建议的解决方案生成一个包含您指定的 JSON 个对象的数组,但如果您想要 JSON 个对象的流,只需省略外部方括号即可。
[group_by(.id)[]
| [map(select(has("team")|not)), map(select(has("team")))]
| combinations
| add]
效率更高...
为了完全避免使用 group_by
或 select
,我们可以使用 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 ]
第一次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"
}
]
]
这是另一个更简洁的解决方案,假设每个 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
)
这个解决方案使用了一种基于combinations
的@JeffMercado 方法的变体,但只使用了一次group_by
(这意味着对于大型数据集,它应该更有效,因为group_by
是一个相对昂贵的操作)。
此处建议的解决方案生成一个包含您指定的 JSON 个对象的数组,但如果您想要 JSON 个对象的流,只需省略外部方括号即可。
[group_by(.id)[]
| [map(select(has("team")|not)), map(select(has("team")))]
| combinations
| add]
效率更高...
为了完全避免使用 group_by
或 select
,我们可以使用 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 ]