在postgres上创建深度嵌套的JSON结构而不必编写非常复杂的缩进查询的简单方法是什么?

在postgres上创建深度嵌套的JSON结构而不必编写非常复杂的缩进查询的简单方法是什么?,json,postgresql,Json,Postgresql,我将几个表连接到一个postgres数据库中,并将右连接表中的值作为聚合JSON结构返回到左连接表中。然而,我发现,连接的表越多,查询就越复杂。例如: select row_to_json(output) from ( select image_type.name, ( select json_agg(instances) from ( select image_instance.name, (

我将几个表连接到一个postgres数据库中,并将右连接表中的值作为聚合JSON结构返回到左连接表中。然而,我发现,连接的表越多,查询就越复杂。例如:

select row_to_json(output)
from (
    select image_type.name,
    (
        select json_agg(instances)
        from (
            select image_instance.name, (
                select json_agg(versions)
                from (
                    select image_version.name
                    from image_version
                    where image_version.image_instance_id = image_version.image_instance_id
                ) versions
            ) AS versions
            from image_instance
            where image_instance.image_type_id = image_type.image_type_id
        ) instances
    ) AS images
    from image_type
) output;

我在这里加入了三个表,但是我想再添加几个表,但是代码很快就会变得很难维护。有没有一种简单的方法来生成这种聚合联接?

首先,当组合来自多个表的数据时,JSON与常规字段没有什么不同:事情可能会很快变得复杂。然而,有一些技巧可以让事情变得易于管理:

1。菊花链功能

不需要独立地处理每个函数的输出,您可以在一条语句中将一个函数的输出作为下一个函数的输入。在您的示例中,这意味着您将丢失每个聚合级别的子选择级别,并且您可以忽略别名。你的例子变成:

select row_to_json(row(image_type.name, (
       select json_agg(image_instance.name, (
              select json_agg(image_version.name)
              from image_version
              where image_version.image_instance_id = image_instance.id) -- join edited
       from image_instance
       where image_instance.image_type_id = image_type.image_type_id))))
from image_type;
2。不要使用标量子查询

这可能是个人喜好的问题,但标量子查询往往很难读取(和写入:您在最内部的标量子查询的连接条件中有一个明显的错误,只是为了说明我的观点)。改用带有显式联接和聚合的常规子查询:

select row_to_json(row(it.name, iiv.name))
from image_type it
join (select image_type_id, json_agg(name, iv_name) as name
      from image_instance ii
      join (select image_instance_id, json_agg(name) as iv_name
            from image_version group by 1) iv on iv.image_instance_id = ii.id
      group by 1) iiv using (image_type_id);
3。模块化

就在那里(强烈推荐阅读,无论你认为自己多么熟练):

充分利用视图是良好SQL数据库的一个关键方面 设计

您的主要查询现在变成:

select row_to_json(row(it.name, ii.name))
from image_type it
join ii_json ii using (image_type_id);
等等

这显然是迄今为止最容易编码、测试和维护的。性能在这里不是问题:查询优化器将把所有链接视图展平到单个执行计划中


最后一点提示:如果您使用的是PG9.4+,您可以使用
json\u build\u object()
而不是
行到行的json()
,以获得更清晰的输出。

@a\u horse\u没有名字的马\u您能在此基础上进行扩展吗?我阅读了您引用的文章,但是我的数据存储在标准化的表中,而不是JSON blob中。我只希望从这些表生成一个JSON主体。也许如果你能扩展一点,它会帮助我理解。谢谢你的回答@Patrick,这是非常全面的,并教会了我如何使用JSON视图。我试着按照您概述的方式来做,但是它们似乎不是嵌套的,而是分组在每列中。您能说明一种将每个连接嵌套为包含聚合的字段的方法吗?如果看不到表结构和所需的输出格式,很难说问题出在哪里,但您可能希望更改
ii_json
视图并放置
json_agg(json_build_object('instance',name',versions',iv_name))
而不是普通的
json\u agg(name,iv\u name)
。与此类似,每一行将有一个JSON对象,该对象具有一个图像类型和一个实例数组,每个实例由一个名称和一个版本数组组成。这就是你想要的吗?
select row_to_json(row(it.name, ii.name))
from image_type it
join ii_json ii using (image_type_id);