PostgreSQL:基于JSON数组中JSON的值对行进行排序

问题描述

一个表说products一个称为identifiers的JSONB列,它存储JSON对象数组。

产品中的样本数据

 id  |     name    |      identifiers
-----|-------------|---------------------------------------------------------------------------------------------------------------
  1  | umbrella    | [{"id": "productID-umbrella-123","domain": "ecommerce.com"},{"id": "amzn-123","domain": "amzn.com"}]
  2  | ball        | [{"id": "amzn-234","domain": "amzn.com"}]
  3  | bat         | [{"id": "productID-bat-234","domain": "ecommerce.com"}]

现在,我必须编写一个查询,该查询根据域“ amzn.com”的“ id”值对表中的元素进行排序

预期结果

 id   |     name     |      identifiers
----- |--------------|---------------------------------------------------------------------------------------------------------------
  3   | bat          |  [{"id": "productID-bat-234","domain": "ecommerce.com"}]
  1   | umbrella     |  [{"id": "productID-umbrella-123","domain": "amzn.com"}]
  2   | ball         |  [{"id": "amzn-234","domain": "amzn.com"}]
amzn.com

id是“ amzn-123”和“ amzn-234”。 按amzn.com的ID排序时,“ amzn-123”首先出现,然后是“ amzn-234”

通过域“ amzn.com”的“ id”值对表格进行排序, ID为3的记录首先出现,因为amzn.com的ID为NULL, 紧接着是ID为1和2的记录,该记录具有已排序的有效ID。

我对如何为该用例编写查询一无所知。 如果它是JSONB而不是JSON数组,我会尝试过。

是否可以在Postgresql中为这种用例编写查询? 如果是,请至少给我一个代码或粗略的查询

解决方法

由于您不知道数组中的位置,因此需要遍历所有数组元素以找到亚马逊ID。

拥有ID后,就可以将其与order by一起使用。使用nulls first会将那些没有亚马逊ID的产品放在顶部。

select p.*,a.amazon_id
from products p
   left join lateral (
      select item ->> 'id' as amazon_id
      from jsonb_array_elements(p.identifiers) as x(item)
      where x.item ->> 'domain' = 'amzn.com'
      limit 1 --<< safe guard in case there is more than one amazon id
   ) a on true --<< we don't really need a join condition
order by a.amazon_id nulls first;

Online example


使用Postgres 12时,时间会短一些:

select p.*
from products p
order by jsonb_path_query_first(identifiers,'$[*] ? (@.domain == "amzn.com").id') nulls first
,

经过几次调整后,这才是最终完成的查询

select p.*,amzn -> 'id' AS amzn_id
from products p left join lateral JSONB_ARRAY_ELEMENTS(p.identifiers) amzn ON amzn->>'domain' = 'amzn.com' 
order by amzn_id nulls first