Find rows by multiple keys and values from json column in postgres - json

I have a table which has a json column and I want to get only the rows that has an specific key an value into the json like this:
here is the an example of the value from that column when I do a simple select query like:
select my_atribute from displays;
result:
{"key": "unit_type", "value": "Tablet", "display_name": "Unit Type"}
{"key": "pack_type", "value": "Packet", "display_name": "Pack Type"}
{"key": "units_in_pack", "value": "60", "display_name": "Units in Pack"}
{"key": "item_unit", "value": "", "display_name": "Item unit"}
{"key": "item_size", "value": "1", "display_name": "Item Size"}
{"key": "details", "value": "", "display_name": "Details"}
{"key": "slug", "value": "otc7087", "display_name": "Slug"}
I want only the rows that have "key" like "slug"or "details" and "display_name" like "Item unit" or "Details"
I've tried the code bellow:
WITH my_table(jsonblob) AS (VALUES ((select my_atribute from displays) :: jsonb))
SELECT elem ->> 'value'
FROM my_table
CROSS JOIN LATERAL jsonb_array_elements(jsonblob) elem
WHERE ((elem ->> 'key') in ('slug', 'details'))
and ((elem ->> 'display_name') in ('Item unit', 'Details'));
and here is the message that I get:
ERROR: more than one row returned by a subquery used as an expression

Related

How to append multiple entries to JSON Array in MySQL?

I am using MySQL 8 and trying to update JSON data type in a mysql table
My table t1 looks as below:
# id group names
1100000 group1 [{"name": "name1", "type": "user"}, {"name": "name2", "type": "user"}, {"name": "techDept", "type": "dept"}]
The JSON format has two types - user and dept
Now, I have a list of users userlist as below:
SET #userlist = '["user4", "user5"]';
I want to append #userlist to the JSON Array:
UPDATE t1 SET names = JSON_ARRAY_APPEND(names, '$', JSON_OBJECT('name', #userlist, 'type', 'user'))
WHERE `group` = 'group1';
The query is working but it is incorrectly adding data as below:
[{"name": "name1", "type": "user"},
{"name": "name2", "type": "user"},
{"name": "["user4", "user5"]", "type": "user"}
{"name": "techDept", "type": "dept"}]
Desired Output:
[{"name": "name1", "type": "user"},
{"name": "name2", "type": "user"},
{"name": "user4", "type": "user"},
{"name": "user5", "type": "user"},
{"name": "techDept", "type": "dept"}]
UPDATE t1
JOIN ( SELECT JSON_ARRAYAGG(JSON_OBJECT('name', username, 'type', 'user')) userlist
FROM JSON_TABLE (#userlist,
'$[*]' COLUMNS (username VARCHAR(255) PATH '$')) jsontable ) jsontable
SET t1.names = JSON_MERGE_PRESERVE(t1.names, jsontable.userlist)
WHERE t1.`group` = 'group1';
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=da25f6643c623d197a220931489864e2

How to query nested array of jsonb

I am working on a PostgreSQL 11 table with a column of nested and multiple jsonb objects
to simulate the issue: -
CREATE TABLE public.test
(
id integer NOT NULL DEFAULT nextval('test_id_seq'::regclass),
testcol jsonb
)
insert into test (testcol) values
('[{"type": {"value": 1, "displayName": "flag1"}, "value": "10"},
{"type": {"value": 2, "displayName": "flag2"}, "value": "20"},
{"type": {"value": 3, "displayName": "flag3"}, "value": "30"},
{"type": {"value": 4, "displayName": "flag4"}},
{"type": {"value": 4, "displayName": "flag4"}},
{"type": {"value": 6, "displayName": "flag6"}, "value": "40"}]');
I am trying to:
get outer value if type= specific value. e.g. get the value 30, if flag3 is in displayname.
count occurrence of flag4 in inner json
You could use json_to_recordset to parse it:
WITH cte AS (
SELECT test.id, sub."type"->'value' AS t_value, sub."type"->'displayName' AS t_name, value
FROM test
,LATERAL jsonb_to_recordset(testcol) sub("type" jsonb, "value" int)
)
SELECT *
FROM cte
-- WHERE ...
-- GROUP BY ...;
db<>fiddle demo

How to flatten json into table

I have just realised on my AWS Aurora postgres cluster having functions with temp_tables are not friendly with read replicas. I need to do a re-write (using CTEs) - anyway.... How do I take a json object with arrays nested and flatten them to a table like so:
{
"data": [
{
"groupName": "TeamA",
"groupCode": "12",
"subGroupCodes": [
"11"
]
},
{
"groupName": "TeamB",
"groupCode": "13",
"subGroupCodes": [
"15", "22"
]
}
]
}
I would like the output table to be:
groupName groupCode subGroupCodes
TeamA 12 11
TeamB 13 15
TeamB 13 22
I know I can get most of the way there with:
SELECT j."groupCode" as int, j."groupName" as pupilgroup_name
FROM json_to_recordset(p_in_filters->'data') j ("groupName" varchar(50), "groupCode" int)
But I just need to get the subGroupCodes as well but unpacking the array and joining to the correct parent groupCodes.
You need to first unnest the array, and then another unnest to get the subgroup codes:
with data (j) as (
values ('{
"data": [
{
"groupName": "TeamA",
"groupCode": "12",
"subGroupCodes": [
"11"
]
},
{
"groupName": "TeamB",
"groupCode": "13",
"subGroupCodes": [
"15", "22"
]
}
]
}'::jsonb)
)
select e ->> 'groupName' as group_name,
e ->> 'groupCode' as code,
sg.*
from data d
cross join lateral jsonb_array_elements(d.j -> 'data') as e(g)
cross join lateral jsonb_array_elements_text(g -> 'subGroupCodes') as sg(subgroup_code)

How to make pgsql return the json array

everyone , I face some issue to convert the data into json object. There is a table called milestone with the following data:
id name parentId
a test1 A
b test2 B
c test3 C
I want to convert the result into a json type in Postgres:
[{"id": "a", "name": "test1", "parentId": "A"}]
[{"id": "b", "name": "test2", "parentId": "B"}]
[{"id": "c", "name": "test3", "parentId": "C"}]
if there are anyone know how to handle , please let me know , thanks all
You can get each row of the table as simple json object with to_jsonb():
select to_jsonb(m)
from milestone m
to_jsonb
-----------------------------------------------
{"id": "a", "name": "test1", "parentid": "A"}
{"id": "b", "name": "test2", "parentid": "B"}
{"id": "c", "name": "test3", "parentid": "C"}
(3 rows)
If you want to get a single element array for each row, use jsonb_build_array():
select jsonb_build_array(to_jsonb(m))
from milestone m
jsonb_build_array
-------------------------------------------------
[{"id": "a", "name": "test1", "parentid": "A"}]
[{"id": "b", "name": "test2", "parentid": "B"}]
[{"id": "c", "name": "test3", "parentid": "C"}]
(3 rows)
You can also get all rows as a json array with jsonb_agg():
select jsonb_agg(to_jsonb(m))
from milestone m
jsonb_agg
-----------------------------------------------------------------------------------------------------------------------------------------------
[{"id": "a", "name": "test1", "parentid": "A"}, {"id": "b", "name": "test2", "parentid": "B"}, {"id": "c", "name": "test3", "parentid": "C"}]
(1 row)
Read about JSON Functions and Operators in the documentation.
You can use ROW_TO_JSON
From Documentation :
Returns the row as a JSON object. Line feeds will be added between
level-1 elements if pretty_bool is true.
For the query :
select
row_to_json(tbl)
from
(select * from tbl) as tbl;
You can check here in DEMO

Redshift - SQL script to extract value from a key value pair

I have a columns containing JSON data as below. I am trying to extract values corresponding to each key pair in the column. Could anyone advice how could I do using SQL
[{"id": 101, "id1": {"key": "SaleId", "type": "identifier", "regex": null}, "id2": {"key": Name, "type": "identifier", "regex": null}, "id3": {"key": null, "type": "identifier", "regex": null}}]
Key values are id1, id2, id3
Expected output:
id1 : SaleId
id2 : Name
id3 : null
I am using Redshift. Thanks
I don't know anything about Redshift, so this might not Work.
It Works in JavaScript:
/"(id\d)":\s\{"key": "?(\w+)"?/g
You will then have to extract Group 1, containing the id and Group 2, containing the key.
The regex starts by matching a double quote, then creating a Group with the Word 'id' followed by a digit, a colon, a Space, a left curly brace, a double quote, the Word 'key', a colon, a Space, an optional double quote. Finally it creates a Group with one or more Word characters, followed by an optional double quote.
As I said, I don't know Redshift, for instance, you might have to escape double quotes.
You can do what you need like this
with t as
(
select '[{"id": 101, ' ||
'"id1": {"key": "SaleId", "type": "identifier", "regex": "null"}, ' ||
'"id2": {"key": "Name", "type": "identifier", "regex": "null"}, ' ||
'"id3": {"key": "null", "type": "identifier", "regex": "null"}}]' as str
)
select 'id1:' || json_extract_path_text(substring(str,2,length(str)-2),'id1','key'),
'id2:' || json_extract_path_text(substring(str,2,length(str)-2),'id2','key'),
'id3:' || json_extract_path_text(substring(str,2,length(str)-2),'id3','key')
from t;
The JSON string in your example is invalid because Name is not in double quotes.
Assuming this is a typo and this is meant to be a valid JSON string, then you can use JSON functions to extract the values you need from the column.
Example (I have added quotes around "Name"):
create temp table jsontest (myjsonstring varchar(1000))
;
insert into jsontest(myjsonstring)
values ('[{"id": 101, "id1": {"key": "SaleId", "type": "identifier", "regex": null}, "id2": {"key": "Name", "type": "identifier", "regex": null}, "id3": {"key": null, "type": "identifier", "regex": null}}]')
;
select 'id1', json_extract_path_text(json_extract_array_element_text(myjsonstring, 0) , 'id1', 'key') from jsontest
union all
select 'id2', json_extract_path_text(json_extract_array_element_text(myjsonstring, 0) , 'id2', 'key') from jsontest
union all
select 'id3', json_extract_path_text(json_extract_array_element_text(myjsonstring, 0) , 'id3', 'key') from jsontest
;