[英]How to aggregate an array of JSON objects with Postgres?
我希望使用 Postgres 聚合一組 JSON 對象,專門用於通過外鍵將關系列表返回到另一個表。 在這種情況下,它是user
和他們的teams
。
這是我正在使用的架構:
CREATE TABLE teams (
id TEXT PRIMARY KEY,
...
);
CREATE TABLE users (
id TEXT PRIMARY KEY,
...
);
CREATE TABLE memberships (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL FOREIGN KEY (user_id) REFERENCES users(id),
team_id TEXT NOT NULL FOREIGN KEY (team_id) REFERENCES teams(id)
);
使用以下查詢:
SELECT
users.id,
...
CASE
WHEN count(teams.*) = 0
THEN '[]'::JSON
ELSE json_agg(DISTINCT teams.id)
END AS teams
FROM users
LEFT JOIN memberships ON users.id = memberships.user_id
LEFT JOIN teams ON teams.id = memberships.team_id
WHERE users.id = $[userId]
GROUP BY
users.id,
...
我可以將結果作為team_id
的平面數組:
{
id: 'user_1',
...
teams: ['team_1', 'team_2']
}
但我想將結果作為 JSON 對象接收:
{
id: 'user_1',
...
teams: [
{ id: 'team_1' },
{ id: 'team_2' }
]
}
我非常接近:
SELECT
users.id,
...
CASE
WHEN count(teams.*) = 0
THEN '[]'::JSON
ELSE json_agg(json_build_object('id', teams.id))
END AS teams
FROM users
LEFT JOIN memberships ON users.id = memberships.user_id
LEFT JOIN teams ON teams.id = memberships.team_id
WHERE users.id = $[userId]
GROUP BY
users.id,
...
但是現在我已經失去了DISTINCT
函數的重復結果刪除功能,所以我最終為每個team
返回了重復的 ID。
您可以使用選擇適當組合的子查詢來解決這個問題,然后聚合到一個json
數組中:
SELECT id, json_strip_nulls(json_agg(json_build_object('id', team))) AS teams
FROM (
SELECT DISTINCT user_id AS id, team_id AS team
FROM memberships
WHERE user_id = $[userId]) sub
GROUP BY id;
您可以從memberships
表中獲取用戶ID 和團隊ID,因此將任一表連接到memberships
表都沒有意義(除非您從這些表中獲取了尚未向我們展示的其他字段)。 如果您確實想使用其他字段,您可以將JOIN
重新粘貼回來。
json_strip_nulls()
函數將去掉[{"id": null}]
出現並用空的[]::json
替換它們。 這是 PG 9.5 的新功能。 這也擺脫了相當丑陋和低效的CASE
子句。
在我看來,這會做到:
SELECT json_build_object(
'id', u.id,
'teams', array_remove(array_agg(DISTINCT t.*), NULL))
FROM users u
LEFT OUTER JOIN memberships m
ON m.user_id = u.id
LEFT OUTER JOIN teams t
ON m.team_id = t.id
GROUP BY u.id
在 9.4 中工作。 對於沒有團隊的用戶來說,刪除NULL
的部分是必要的。
我懷疑在 Postgres 中做 JSON 的一個很好的一般原則是盡可能長時間地堅持使用數組和記錄,並且只在最后時刻切換到 JSON。 更傳統的結構存在的時間更長並且與關系模型的聯系更緊密,因此您在使用它們時遇到問題的可能性較小。 你可以看到這個查詢可能有很容易地返回指定的列id
和數組值列命名的teams
。
請注意,此查詢為所有用戶提供。 如果你只想要一個,把它放在WHERE
子句中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.