Transform JSON map to an array in Postgres via update statement - sql

I have a postgresql table called datasource with jsonb column called data. It has the following structure:
{
"key1":{"param1" : "value1", "param2" : "value2"},
"key2":{"param2_1" : "value2_1", "param2_2" : "value2_2"},
"key3":{"param3_1" : "value3_1", "param3_2" : "value3_2"}
}
Is there any way to write some UPDATE script to transform given JSON to the following:
[
{"key": "key1", "param1" : "value1", "param2" : "value2"},
{"key": "key2", "param2_1" : "value2_1", "param2_2" : "value2_2"},
{"key": "key3", "param3_1" : "value3_1", "param3_2" : "value3_2"}
]

You can unnest the object to rows in a lateral join, then aggregate back into an array:
select d.*, x.*
from datasource d
cross join lateral (
select jsonb_agg(jsonb_build_object('key', j.k) || j.v) new_data
from jsonb_each(d.data) as j(k, v)
) x
Demo on DB Fiddle - with jsonb_pretty() enabled:
If you wanted an update statement:
update datasource d
set data = (
select jsonb_agg(jsonb_build_object('key', j.k) || j.v)
from jsonb_each(d.data) as j(k, v)
)

Related

how can I make result of ARRAY_AGG() function json parsable

I have a query that selects the rows from joined table as an array using ARRAY_AGG() function.
select
entity_number,
ARRAY_AGG('{"property_id":"'||property_id||'","value":"'||value||'"}') entity_properties from entities
join entity_properties
on entities.id = entity_properties.entity_id
where entities.id in (
select entity_id from entity_properties
where value = '6258006d824a25dabdb39a79.pdf'
)
group by entities.id;
what I get is:
[
{
"entity_number":"P1718238009-1",
"entity_properties":"[
\"{\"property_id\":\"006109cd-a100-437c-a683-f13413b448e6\",\"value\":\"Rozilik berildi\"}\",
\"{\"property_id\":\"010f5e23-d66f-4414-b54b-9647afc6762b\",\"value\":\"6258006d824a25dabdb39a79.pdf\"}\",
\"{\"property_id\":\"0a01904e-1ca0-40ef-bbe1-c90eaddea3fc\",\"value\":\"6260c9e9b06e4c2cc492c470_2634467.pdf\"}\"
]"
}
]
As you can see, it is not json parsable
To parse entity_properties as array of objects I need the data in this format
[
{
"entity_number":"P1718238009-1",
"entity_properties":[
{"property_id":"006109cd-a100-437c-a683-f13413b448e6","value":"Rozilik berildi"},
{"property_id":"010f5e23-d66f-4414-b54b-9647afc6762b","value":"6258006d824a25dabdb39a79.pdf"},
{"property_id":"0a01904e-1ca0-40ef-bbe1-c90eaddea3fc","value":"6260c9e9b06e4c2cc492c470_2634467.pdf"}
]
}
]
Can I achieve what I want with ARRAY_AGG()? How?
If not, what approach should I take?
Try using json_agg and json_build_object function
like this:
select
entity_number,
json_agg(json_build_object('property_id', property_id, 'value', value)) entity_properties from entities
join entity_properties
on entities.id = entity_properties.entity_id
where entities.id in (
select entity_id from entity_properties
where value = '6258006d824a25dabdb39a79.pdf'
)
group by entities.id;
Using a simplified sample data this query provides the first step of the aggregation
with tab as (
select * from (values
(1,'a','x'),
(1,'b','y'),
(2,'c','z')
) tab(entity_number,property_id,value)
)
select
entity_number,
json_agg( json_build_object('property_id', property_id, 'value', value)) entity_properties
from tab
group by 1
;
entity_number|entity_properties |
-------------+----------------------------------------------------------------------------+
1|[{"property_id" : "a", "value" : "x"}, {"property_id" : "b", "value" : "y"}]|
2|[{"property_id" : "c", "value" : "z"}]
Additional aggregation returns the final json array
with tab as (
select * from (values
(1,'a','x'),
(1,'b','y'),
(2,'c','z')
) tab(entity_number,property_id,value)
),
tab2 as (
select
entity_number,
json_agg( json_build_object('property_id', property_id, 'value', value)) entity_properties
from tab
group by 1
)
select
json_agg(
json_build_object(
'entity_number',
entity_number,
'entity_properties',
entity_properties
)
)
from tab2
[
{
"entity_number": 1,
"entity_properties": [
{
"value": "x",
"property_id": "a"
},
{
"value": "y",
"property_id": "b"
}
]
},
{
"entity_number": 2,
"entity_properties": [
{
"value": "z",
"property_id": "c"
}
]
}
]
Note that I used jsonb_pretty to format the output.

Equivalent of jsonb_path_query_array in Postgresql-11

[
{
"name" : "A",
"key" : "KA"
},
{
"name" : "B",
"key" : "KB"
}
]
Given a column containing the above data,
I use select jsonb_path_query_array(column, '$.key') to get the output [KA, KB]
However this doesn't work in Postgres-11. Are there any alternatives for the same ?
Yes. This yields a Postgres array. Use jsonb_agg instead of array_agg if you need a JSON array.
select array_agg(j ->> 'key')
from jsonb_array_elements(column) t(j);
Update
select
(select array_agg(j ->> 'key') from jsonb_array_elements(column) t(j))
from the_table;

Creating json from Oracle database table

Hi I have to create json file from Oracle table. I have data in the below form.
I want data in this format.
{
"add" :
[
{
"canonicalName" : "Apple Computers",
"synonyms" :
[
"Apple",
"Apple Inc"
]
},
{
"canonicalName" : "Google India",
"synonyms" :
[
"Google"
]
},
{
"canonicalName" : "IBM",
"synonyms" :
[
"IBM Corporation"
]
}
],
"delete" :
[
{
"canonicalName" : "IBM",
"synonyms" :
[
"IBM Corporation"
]
},
{
"canonicalName" : "TCS"
}
],
"update" :
[
{
"canonicalName" : "Infosys",
"synonyms" :
[
"Infosys Tech"
]
},
{
"canonicalName" : "Wipro Tech",
"synonyms" :
[
"Wipro Technology"
]
}
]
}
the below code is working properly.
with
prep (operation, orgname, fragment) as (
select operation, orgname,
json_object( key 'canonicalName' value orgname,
key 'synonyms'
value nullif(json_arrayagg(synonyms order by synonyms), '[]')
FORMAT JSON ABSENT ON NULL
)
from t
group by orgname, operation
)
select json_objectagg( key operation
value json_arrayagg(fragment order by orgname)
) as json_str
from prep
group by operation;
Now I have to add one extra column in this table.
so column tablename contains "ORG" and "ITEM" values. so I have to create 2 files one would be item.json and another one would be ORG.json and so on.
I need to put data which has ITEM in item.json and which has ORG in ORG.json.
what changes i need to do in above query.
Even PL/SQL would be OK. Can you suggest changed on above query?
It would be also fine if we can store the result into some array and return to calling environment
Here is one approach. You don't need to know the values in the TABLENAME column in advance. Rather, the query output will have one row per unique value in TABLENAME, presented in two columns: the TABLENAME and the corresponding JSON string for that TABLENAME.
with
prep1 (tablename, operation, orgname, fragment) as (
select tablename, operation, orgname,
json_object( key 'canonicalName' value orgname,
key 'synonyms'
value nullif(json_arrayagg(synonyms order by synonyms), '[]')
FORMAT JSON ABSENT ON NULL
)
from t
group by tablename, orgname, operation
)
, prep2 (tablename, operation, org_str) as (
select tablename, operation, json_arrayagg(fragment order by orgname)
from prep1
group by tablename, operation
)
select tablename, json_objectagg(key operation value org_str) as json_str
from prep2
group by tablename
;
TABLENAME JSON_STR
--------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ITEM {"add":[{"canonicalName":"Apple Computers","synonyms":["Apple","Apple Inc"]},{"canonicalName":"Google India","synonyms":["Google"]},{"canonicalName":"IBM","synonyms":["IBM Corporation"]}],"update":[{"canonicalName":"Infosys","synonyms":["Infosys Tech"]},{"canonicalName":"Wipro Tech","synonyms":["Wipro Technology"]}],"delete":[{"canonicalName":"IBM","synonyms":["IBM Corporation"]},{"canonicalName":"TCS"}]}
ORG {"add":[{"canonicalName":"Apple Computers","synonyms":["Apple","Apple Inc"]},{"canonicalName":"Google India","synonyms":["Google"]},{"canonicalName":"IBM","synonyms":["IBM Corporation"]}],"update":[{"canonicalName":"Infosys","synonyms":["Infosys Tech"]},{"canonicalName":"Wipro Tech","synonyms":["Wipro Technology"]}],"delete":[{"canonicalName":"IBM","synonyms":["IBM Corporation"]},{"canonicalName":"TCS"}]}

Set a json objects values from an array in postgresql

I have an Array of JSON objects in PostgreSQL inside data.json, That looks like this
[
{ "10" : [1,2,3,4,5] },
{ "8" : [5,4,3,1,2] },
{ "11" : [1,3,5,4,2] }
]
The data is taken from a select statement
SELECT
ARRAY((SELECT json_build_object(station_id,
ARRAY((SELECT
COALESCE((SELECT SUM(prodtakt_takt)
FROM psproductivity.prodtakt
WHERE prodtakt_start::date = generate_series.shipping_day_sort::date
AND station_id = prodtakt_station_id
),0)
FROM generate_series)) ) FROM psproductivity.station WHERE (SELECT COALESCE(SUM(prodtakt_takt),0) FROM psproductivity.prodtakt WHERE station_id = prodtakt_station_id) > 0
)) AS json, ...
Where generate_series is just a series of dates.
Now I need to that and turn it into this format of a JSON object
{
"x" : "x",
"jsondata" : {
"10" : [1,2,3,4,5]
"8" : [5,4,3,1,2]
"11" : [1,3,5,4,2]
}
}
the software I am working on uses c3.js to process data into graphs so I have to change this format. I am thinking that I need to start with something like
json_build_object( 'jsondata',( SELECT FROM json_each(unnest(data.json)) ) )
But I can think of no route with that logic. Adding the x into the JSON object is easy. I am confident I can do that part if I can just reorganize the array

Postgres: How to alter jsonb value type for each element in an array?

I have a jsonb column named items in Postgres 10.12 like this:
{
"items": [
{
"itemQty": 2,
"itemName": "snake"
},
{
"itemQty": 1,
"itemName": "x kodiyum"
}
]
}
Now I want to convert itemQty type to string for every array element so that the new values are like this:
{
"items": [
{
"itemQty": "2",
"itemName": "snake"
},
{
"itemQty": "1",
"itemName": "x kodiyum"
}
]
}
How do I do this? I have gone through the documentation for Postgres jsonb and couldn't figure out.
On the server-side, I am using Spring boot and Hibernate with com.vladmihalcea.hibernate.type.json (Hibernate Types 52) if it helps.
Thanks
You could unnest the array, modify the elements, and then rebuild it. Assuming that the primary key of your table is id, that would be:
select jsonb_build_object(
'items', jsonb_agg(
jsonb_build_object(
'itemQty', (x.obj ->> 'itemQty')::text,
'itemName', x.obj ->> 'Name'
)
)
)new_items
from mytable t
cross join lateral jsonb_array_elements(t.items -> 'items') as x(obj)
group by id
Note that the explicit cast to ::text is not really needed here, as ->> extract text values anyway: I kept it because it makes the intent clearer.
If you want an update statement:
update mytable t
set items = (
select jsonb_build_object(
'items', jsonb_agg(
jsonb_build_object(
'itemQty', (x.obj ->> 'itemQty')::text,
'itemName', x.obj ->> 'Name'
)
)
)
from jsonb_array_elements(t.items -> 'items') as x(obj)
)
Demo on DB Fiddle