在 jsonb 列上查询和计数

Query and count on jsonb column

我是 postgreSQL(9.5) Json 世界的新手。寻求编写此查询的帮助。以这个简化的table为例。

CREATE TABLE activity_log (uri varchar,
                           data jsonb );

'data' 列内的数据示例。

"{"ListingInputFilterBean":{"searchItems": [], "listingStatus": "ACTIVE"}"

"{"ListingInputFilterBean":{"searchItems": [{"name": "Dachshund", "type": "BREED"}], "listingStatus": "ACTIVE"}}"

"{"ListingInputFilterBean":{"searchItems": [{"name": "Lab", "type": "BREED"}, {"name": "Black Lab", "type": "CST"}], "listingStatus": "ACTIVE"}}"

'data' 列用于记录每个 URI 调用的特定数据集。在这种情况下,searchItems 数组包含搜索中使用的项目。我希望编写一个查询来查找搜索次数最多的 'breed'。当类型为 'BREED' 时,我想计算每个 'name' 被使用的次数。

我最初的方法是撤回每个 'searchItems'。使用 jsonb_to_recordset 将它们变成行集,但在阅读文档时我很快就陷入困境(抱歉,我是菜鸟)。

关于如何写 SQL 有什么建议吗?

WITH log_activity(data) AS ( VALUES
  ('{"ListingInputFilterBean":{"searchItems": [], "listingStatus": "ACTIVE"}}'::JSONB),
  ('{"ListingInputFilterBean":{"searchItems": [{"name": "Dachshund", "type": "BREED"}], "listingStatus": "ACTIVE"}}'::JSONB),
  ('{"ListingInputFilterBean":{"searchItems": [{"name": "Lab", "type": "BREED"}, {"name": "Black Lab", "type": "CST"}], "listingStatus": "ACTIVE"}}'::JSONB)
)
SELECT search_item->>'name',count(search_item->>'name')
FROM
  log_activity la,
  jsonb_array_elements(la.data#>'{ListingInputFilterBean,searchItems}') as search_item
WHERE search_item->>'type' = 'BREED'
GROUP BY search_item;

结果:

   name    | count 
-----------+-------
 Lab       |     1
 Dachshund |     1
(2 rows)

在这里您只需要遍历 searchItems 的列表并仅对那些符合您的条件的条目进行分组。步骤如下:

  1. #>运算符得到searchItemsjsonb数组,会得到指定路径下的JSON对象;
  2. 使用 jsonb_array_elements() 函数遍历步骤 1 中检索到的元素列表,该函数将 JSON 数组扩展为一组 JSON 值;
  3. count() names where searchItems' type = BREED, 你可以用 ->> 运算符得到实际的文本值;

更新

使用 jsonb_to_recordset() 看起来更短,但您需要明确定义 search_item 列的类型:

SELECT search_item.name ,count(search_item.name)
FROM
  log_activity la,
  jsonb_to_recordset(la.data#>'{ListingInputFilterBean,searchItems}') as search_item(name text,type text)
WHERE search_item.type = 'BREED'
GROUP BY search_item.name;