Reputation: 109
I have the following table in Aurora Postgres:
create table newtable(column1 jsonb);
insert into newtable(column1) values
('{"usertype":[{"type":"staff","status":"active","permissions": {"1": "add user","2": "add account"}}
, {"type":"customer","status":"suspended"}
, {"type":"corporate","status":"active"}]}');
I can get to a certain degree of data selection using the LATERAL
query syntax. But I need help with querying one level deeper.
PLEASE Ignore: the additional rows selected as I tried a few formats.
SELECT json_line_item ->> 'type' as "type", json_line_item ->> 'status' as "status" , json_line_item->>'permissions' "permissions"
FROM newtable
, LATERAL jsonb_array_elements(newtable.column1 -> 'usertype') json_line_item;
I want the permissions column as a list without any extra double quotes.
Another option is to get one single permissions by filtering (for eg: permissions[1]
or permissions[2]
etc.
Upvotes: 1
Views: 1010
Reputation: 656754
I want the permissions column as a list without any extra double quotes.
Use jsonb_each_text()
in another LATERAL
subquery to extract (key and) object values, then concatenate the list with string_agg()
:
SELECT id
, js_line_item ->> 'type' AS type
, js_line_item ->> 'status' AS status
, js_line_item ->> 'permissions' AS permissions
, p.permission_list -- !
FROM newtable n
LEFT JOIN LATERAL jsonb_array_elements(n.column1 -> 'usertype') AS js_line_item ON true
CROSS JOIN LATERAL (
SELECT string_agg(value, ', ') AS permission_list
FROM jsonb_each_text(js_line_item -> 'permissions')
) p;
db<>fiddle here
Use LEFT JOIN LATERAL
to retain all rows even without "usertype" data. I added an id
to make that clearer. CROSS JOIN
like before would eliminate such rows from the result.
The added table expression can be joined with a CROSS JOIN
because a subquery with an aggregate function and no GROUP BY
always returns a single aggregated row.
... get one single permissions by filtering (for eg: permissions[1] or permissions[2] etc.
SELECT id
, js_line_item ->> 'type' AS type
, js_line_item ->> 'status' AS status
, js_line_item -> 'permissions' ->> '1' AS permission_1 -- !
, js_line_item #>> '{permissions, 2}' AS permission_2 -- !
-- , js_line_item['permissions']['3'] AS permission_3 -- ! ① for pg 14
FROM newtable n
LEFT JOIN LATERAL jsonb_array_elements(n.column1 -> 'usertype') AS js_line_item ON true;
db<>fiddle here
In (current) Postgres 13 you cannot iterate through objects of a record with subscripts like . That only works for arrays.permissions[1]
I added two syntax variants for Postgres 13.
① The third syntax variant requires Postgres 14, using the new "jsonb
subscripting".
Use quoted key names to extract values from objects, and ordinal integer positions (starting at 0) to extract elements from arrays.
3
in our example js_line_item['permissions']['3']
is a key name and has to be quoted.
If a
jsonb
value is an array, numeric subscripts start at zero, and negative integers count backwards from the last element of the array. Slice expressions are not supported.
Upvotes: 1