Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Postgres JSONB query about nested/recursive elements

I have a nested and hierarchical structure expressed in JSON e.g.:

{
   "id":1,
   "children": [
      { "id":2 },
      { "id": 3, "children": [
         { "id": 4 }
         ]
      }
   ]
}

Can postgres answer a query whether the record contains "id": 4 in any part of the document?

If yes, are such queries backed by JSONB indexing added in version 9.4?

like image 806
Karol Kolenda Avatar asked Jul 11 '26 20:07

Karol Kolenda


1 Answers

UPDATE: Thanks to therealgaxbo on reddit, we started with my original code and developed something more concise:

with recursive deconstruct (jsonlevel) as(
    values ('{"id":1,"children":[{"id":2},{"id":3,"children":[{"id":4}]}]}'::json)

    union all

    select 
        case left(jsonlevel::text, 1)
            when '{' then (json_each(jsonlevel)).value
            when '[' then json_array_elements(jsonlevel)
        end as jsonlevel
    from
        deconstruct
    where
        left(jsonlevel::text, 1) in ('{', '[')
)
select * from deconstruct where case when left(jsonlevel::text, 1) = '{' then jsonlevel->>'id' = '4' else false end;

My original response below:

I experimented like crazy and finally came up with something like this:

with recursive ret(jsondata) as
(select row_to_json(col)::text jsondata from 
json_each('{
   "id":1,
   "children": [
      { "id":2 },
      { "id": 3, "children": [
         { "id": 4 }
         ]
      }
   ]
}'::json) col
union 
select case when left(jsondata::text,1)='[' then row_to_json(json_each(json_array_elements(jsondata)))::text
when left((jsondata->>'value'),2)='{}' then null::text
when left((jsondata->>'value')::text,1)='[' then row_to_json(json_each(json_array_elements(jsondata->'value')))::text
else  ('{"key":'||(jsondata->'key')||', "value":'||(jsondata->'value')||'}')::json::text end jsondata 
from (
select row_to_json(json_each(ret.jsondata::json)) jsondata
from ret) xyz

)
select max(1) from ret
where jsondata::json->>'key'='id' 
and jsondata::json->>'value'='1'
like image 82
Joe Love Avatar answered Jul 14 '26 08:07

Joe Love



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!