如何使用 Postgres 聚合 JSON 对象数组?

Ian*_*lor 6 sql postgresql json

我希望使用 Postgres 聚合 JSON 对象数组,特别是通过外键将关系列表返回到另一个表。在本例中,它是 auser和 他们的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)
);
Run Code Online (Sandbox Code Playgroud)

通过以下查询:

  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,
    ...
Run Code Online (Sandbox Code Playgroud)

我可以得到结果作为 s 的平面数组team_id

{
  id: 'user_1',
  ...
  teams: ['team_1', 'team_2']
}
Run Code Online (Sandbox Code Playgroud)

但我想接收 JSON 对象形式的结果:

{
  id: 'user_1',
  ...
  teams: [
    { id: 'team_1' },
    { id: 'team_2' }
  ]
}
Run Code Online (Sandbox Code Playgroud)

我非常接近:

  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,
    ...
Run Code Online (Sandbox Code Playgroud)

但现在我已经失去了该函数DISTINCT的重复结果删除功能,因此我最终为每个team.

Pat*_*ick 6

您可以使用子查询来解决此问题,该子查询选择适当的组合,然后聚合到一个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;
Run Code Online (Sandbox Code Playgroud)

您可以从表中获取用户 ID 和团队 ID memberships,因此将任一表连接到memberships表中都没有意义(除非您从那些表中获取了未向我们展示的其他字段)。如果您确实想使用其他字段,您可以将JOINs 粘贴回去。

json_strip_nulls()函数将消除[{"id": null}]出现的情况并将其替换为空[]::json。这是PG 9.5的新功能。这也摆脱了相当丑陋和低效的CASE条款。