简体   繁体   中英

Query and count on jsonb column

I'm new to the postgreSQL(9.5) Json world. Looking for help writing this query. Take this simplified table as an example.

CREATE TABLE activity_log (uri varchar,
                           data jsonb );

Example of data inside of 'data' column.

"{"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"}}"

The 'data' column is used to log specific sets of data for each URI call. In this case the searchItems array contain the items used in the search. I'm looking to write a query that finds the most searched for 'breed'. I'd like to count the number of times each 'name' is used when type is 'BREED'.

My initial approach was to pull back each of the 'searchItems'. Turn those into a row set using jsonb_to_recordset, but I quickly got in over my head when reading the documentation (sorry, I'm a noob).

Any suggestions on how to write that 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;

Result:

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

Here you just need to iterate over the list of searchItems and group only those entries, which do match your criteria. Steps are the following:

  1. Get jsonb array of searchItems with #> operator, it will get JSON object at specified path;
  2. Iterate over the list of elements retrieved from step 1 with jsonb_array_elements() , function which expands a JSON array to a set of JSON values;
  3. count() names where searchItems' type = BREED , you can get actual text value with ->> operator;

UPDATE

With jsonb_to_recordset() it looks shorter, but you need explicitly define search_item columns' types:

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM