双嵌套 array_agg(row_to_json())

Double nested array_agg(row_to_json())

我有三个表:人,宠物,小狗。

一个人可以养很多只宠物。 一只宠物可以养很多只小狗。

我构建我的架构并插入数据,如下所示:

create table person (
  id serial primary key,
  name text
);

create table pet (
  id serial primary key,
  owner int,
  name text
);

create table pup (
  id serial primary key,
  parent int,
  name text
);

insert into person (name) values
('tom'), ('dick'), ('harry');

insert into pet (owner, name) values
(1, 'fluffy'),
(2, 'snuffles'),
(1, 'mr potato head');

insert into pup (parent, name) values
(1, 'fluffy jr'),
(1, 'fluffy II');

我们看到“tom”这个人有两只宠物“fluffy”和“mr potato head”。 我们看到人“dick”有一只宠物“snuffles”。

我们看到宠物“fluffy”有两只幼崽“fluffy jr”和“fluffy II”。

我想得到一个双层嵌套数组,但我只能得到一层嵌套。这是我的 sql fiddle - http://sqlfiddle.com/#!17/03659/2 他们查询我使用:

select p.*,
       array_agg(row_to_json(
         pet
       )) filter (where pet.id is not null) as pets
from person p
left outer join pet pet
on pet.owner = p.id
group by p.id;

我希望的是为“pups”双重嵌套输入“tom”:

{
  "id": 1,
  "name": "tom",
  {
    "id": 1,
    "owner": 1,
    "name": "fluffy",
    "pups": [
      {
        "id": 1,
        "parent": 1,
        "name": "fluffy jr"
      },
      {
        "id": 2,
        "parent": 1,
        "name": "fluffy II"
      }
    ]
  }
}

有人知道如何获得这种双重嵌套吗?

您可以在子查询中按 parent 聚合“小狗”,然后在外部查询中按人聚合:

select pn.*,
    jsonb_agg(jsonb_build_object(
        'id',    pt.id,
        'owner', pt.owner,
        'name',  pt.name,
        'pups',  pp.pups
    )) filter(where pt.id is not null) pets
from person pn
left join pet pt 
    on pt.owner = pn.id
left join (select parent, jsonb_agg(pp) pups from pup pp group by parent) pp 
    on pp.parent = pt.id
group by pn.id;

请注意,这使用 JSON 聚合函数 json[b]_agg() 生成 JSON 数组而不是 array_agg()。我也从 json 切换到 jsonb - 后者应该是首选,因为它提供了比前者更多的功能。