如何在 jsonb 对象数组上应用过滤器 - 聚合后?

How to apply a filter on jsonb array of objects - after aggregating?

我有一个遵循 select 的声明:

SELECT 
    cards.*, 
    COUNT(cards.*) OVER() AS full_count, 
    p.printing_information 
FROM 
    cards
LEFT JOIN 
    (SELECT 
         pr.card_id, jsonb_agg(to_jsonb(pr)) AS printing_information
     FROM 
         printings pr
     GROUP BY 
         pr.card_id) p ON cards.card_id = p.card_id 
WHERE 
    ...

我希望能够查询 printings table 中的 set_id。我试图在上面的 select 语句中通过包含 pr.set_id 来做到这一点,但它随后需要一个 GROUP BY pr.card_id, pr.set_id 然后每次打印一行而不是在 printing_information 中打印所有内容子数组。

除非我确定如何执行上述操作,否则是否可以在 jsonb 的 printing_information 数组中进行搜索?

理想情况下,我希望能够做类似的事情:

WHERE p.printing_information->set_id = '123'

不幸的是我不能这样做,因为它在一个数组中。

实现此目标的最佳方法是什么?我可以对结果进行 post 处理以去除不必要的结果,但我觉得一定有更好的方法。

SELECT cards.*
     , count(cards.*) over() AS full_count
     , p.printing_information
FROM   cards
LEFT   JOIN (
   SELECT pr.card_id, jsonb_agg(to_jsonb(pr)) AS printing_information
   FROM   printings pr
   WHERE  pr.set_id = '123'            -- HERE!
   GROUP  BY pr.card_id
   ) p ON cards.card_id = p.card_id
WHERE  ...

这比事后过滤 便宜得多。并且可以通过 (set_id) 上的索引来支持 - 不同于任何在动态生成的 jsonb 列上进行过滤的尝试。

这很有效,但无论如何我们都需要聚合 table printings 中的所有或大部分行。但是您添加的 WHERE ... 意味着在外部 SELECT 上有更多过滤器。如果这导致只需要 printings 中的几行,则 LATERAL 子查询应该更有效:

SELECT cards.*
     , count(cards.*) OVER() AS full_count
     , p.printing_information
FROM   cards c
CROSS  JOIN LATERAL (
   SELECT jsonb_agg(to_jsonb(pr)) AS printing_information
   FROM   printings pr
   WHERE  pr.card_id = c.card_id
   AND    pr.set_id = '123'    -- here!
   ) p
WHERE  ...  -- selective filter here?!?

参见:

另外,这里没有“jsonb 数组”。子查询生成一个 jsonb 包含一个数组。