由于JSON支持,我正在考虑切换到PostgreSQL。但是,我想知道,是否可以通过单个查询进行以下操作:
假设有两个表:
表1)组织:
ID (INT) | members (JSONB) |
------------+---------------------------------------------------------|
1 | [{ id: 23, role: "admin" }, { id: 24, role: "default" }]|
2 | [{ id: 23, role: "user" }]
表2)用户:
ID (INT) | name TEXT | email TEXT |
------------+-----------+---------------|
23 | Max | max@gmail.com |
24 | Joe | joe@gmail.com |
现在我想得到这样的结果(我所拥有的只是组织[1]的ID):
ID (INT) | members (JSONB) |
------------+--------------------------------------------------------|
1 | [{ id: 23, name: "Max", email: "max@gmail.com", role:
"admin" },
{ id: 24, name: "Joe", email: "joe@gmail.com ", role:
"default" }]
(1 row)
我知道这不是JSONB的目的,并且有一个更好的解决方案可以将这些数据存储在SQL中,但是我很好奇是否有可能。
谢谢!
答案 0 :(得分:0)
可能有更多方法可以做到这一点。一种方法是使用jsonb_to_recordset()
将JSON转换为可以连接的记录集。然后使用jsonb_build_object()
为各个成员创建一个JSON,并使用jsonb_agg()
将这些结果聚合到JSON数组中。
SELECT jsonb_agg(jsonb_build_object('id', "u"."id",
'name', "u"."name",
'email', "u"."email",
'role', "m"."role"))
FROM "organisations" "o"
CROSS JOIN LATERAL jsonb_to_recordset(o."members") "m" ("id" integer,
"role" text)
INNER JOIN "users" "u"
ON "u"."id" = "m"."id";
具体可用的功能取决于版本。但是,既然您说过要考虑进行切换,那么假设更新版本应该是合理的。
答案 1 :(得分:0)
是的,Postgres可以满足此要求。这是9.6或更高版本的解决方案。
SELECT o.id,
JSON_AGG(
JSON_BUILD_OBJECT('id', u.id, 'name', u.name, 'email', u.email, 'role', e.usr->'role')
)
FROM organisations o
INNER JOIN LATERAL JSONB_ARRAY_ELEMENTS(o.data) AS e(usr) ON TRUE
INNER JOIN users u ON (e.usr->'id')::text::int = u.id
GROUP BY o.id
请参见this db fiddle。
说明:
JSONB_ARRAY_ELEMENTS
函数将组织json数组拆分为行(每个用户一个);它通常与JOIN LATERAL
要加入users
表,我们使用id
运算符访问->
字段的内容
对于每个用户,JSONB_BUILD_OBJECT
用于通过传递值/键对列表来创建新对象;大多数值来自users
表,role
除外,该表取自组织json元素
查询按组织ID进行汇总,使用JSONB_AGG
通过组合上述对象来生成json数组
有关更多信息,您还可以查看Postgres JSON Functions documentation。