Postgresql 嵌套数组中的排序\u agg查询

Postgresql 嵌套数组中的排序\u agg查询,postgresql,Postgresql,我使用此查询的目标是从communities表中提取所有内容,以及从联接中提取jsonb对象的数组_agg。这在未排序的情况下可以正常工作,因此: select communities.*, ( select array_agg(jsonb_build_object('id', community_permissions.document_id)) from documents as conversations join community_permissions

我使用此查询的目标是从communities表中提取所有内容,以及从联接中提取jsonb对象的数组_agg。这在未排序的情况下可以正常工作,因此:

select communities.*,
  (
    select array_agg(jsonb_build_object('id', community_permissions.document_id))
    from documents as conversations
      join community_permissions on community_permissions.document_id = conversations.id
        where conversations.published = true
        and community_permissions.community_id = communities.id
  ) as conversations
  from communities where communities.id = 110;
这将为社区中的列返回一个包含普通列的行,并在conversations列中返回一个类似[{id:1},{id:2}…]的json数组。一切都很好,查询工作得很好,我可以在SQL中声明性地一次获取一行及其重要关系。我甚至可以从不同的表中筛选连接的返回值,仅在该列表中返回已发布的对话

我现在要做的是根据documents表中别名为上述对话的属性对对话进行排序。天真的方法:

select communities.*,
  (
    select array_agg(jsonb_build_object('id', community_permissions.document_id))
    from documents as conversations
      join community_permissions on community_permissions.document_id = conversations.id
        where conversations.published = true
        and community_permissions.community_id = communities.id
        order by conversations.updated_at desc
  ) as conversations
  from communities where communities.id = 110;
不起作用-列walker希望conversations.updated_at值位于group_by子句中。如果我添加一个group by子句,如下所示:

select communities.*,
  (
    select array_agg(jsonb_build_object('id', community_permissions.document_id))
    from documents as conversations
      join community_permissions on community_permissions.document_id = conversations.id
        where conversations.published = true
        and community_permissions.community_id = communities.id
        group by conversations.updated_at
        order by conversations.updated_at desc
  ) as conversations
  from communities where communities.id = 110;
看起来数组_agg不再实际聚合响应-我收到一个错误,该错误由用作表达式的子查询返回多行。我可以在order by之后设置一个限制1,然后执行查询,但是在array_agg列中我只得到一个对话——至少是最近的一个。所以可以说,array_agg实际上并没有聚合到一个数组中

我可以通过将整个东西拆开并使用CTE进行查询:

with q1 as (
  select conversations.id as id, community_permissions.community_id as community_id
  from documents as conversations
  join community_permissions on community_permissions.document_id = conversations.id
  where conversations.published = true order by conversations.updated_at desc
)
select communities.id, (
  select array_agg(jsonb_build_object('id', q1.id))) as conversations 
  from communities join q1 on q1.community_id = communities.id
  where communities.id = 110
  group by communities.id;
但这是非常低效的,解释者指出每次查询运行时它都在对整个对话表进行排序,并且任何给定的社区只有一小部分对话表通过社区权限与它共享


这也是令人不满意的,因为我正在尝试模块化查询,以便后端可以决定,嘿,您需要这些值,并将它们放入SQL查询中,然后在单个查询中一次完成所有操作,与其拉社区,然后手动查询每个关系,通常不止一个-社区有成员、对话、追随者等。最坏的情况下,我可以这样做-只需在后端节点层处理额外的抓取并在那里组装,但是,在我需要这种排序功能之前,将其全部放在子查询中似乎更为优雅。

其中一位写了一篇关于stackoverflow的长文章,并在十分钟后找到了答案

我的诀窍是,为了将来的参考,我把订单放在了错误的地方。这项工作:

select communities.*,
  (
    select array_agg(jsonb_build_object('id', community_permissions.document_id) order by conversations.updated_at desc)
    from documents as conversations
      join community_permissions on community_permissions.document_id = conversations.id
      where conversations.published = true
      and community_permissions.community_id = communities.id
  ) as conversations
  from communities where communities.id = 110;

请注意,order by现在位于array_agg调用中,而不是子查询中。

其中一位写了一篇关于stackoverflow的长文章,并在十分钟后找到答案

我的诀窍是,为了将来的参考,我把订单放在了错误的地方。这项工作:

select communities.*,
  (
    select array_agg(jsonb_build_object('id', community_permissions.document_id) order by conversations.updated_at desc)
    from documents as conversations
      join community_permissions on community_permissions.document_id = conversations.id
      where conversations.published = true
      and community_permissions.community_id = communities.id
  ) as conversations
  from communities where communities.id = 110;

请注意,order by现在位于array_agg调用中,而不是在子查询中。

您可以在聚合函数中指定顺序

尝试:


可以在聚合函数中指定顺序

尝试: