I have a column with the following text data (2 rows):
{"{john,m,25.01.1980}","{steve,m,12.12.1995}","{kate,f,17.04.1990}"}
{"{max,m,26.01.1980}","{sarah,f,18.04.1990}"}
This need to be converted into json like this (2 rows):
[{ "birth_date": 1234567890, "name": "john", "gender": "m" }, { "birth_date": 1234567890, "name": "steve", "gender": "m" }, { "birth_date": 1234567890, "name": "kate", "gender": "f" }]
[{ "birth_date": 1234567890, "name": "max", "gender": "m" }, { "birth_date": 1234567890, "name": "sarah", "gender": "f" }]
I have tried to use UNNEST, row_to_json and json_build_object, but cannot fugure out how to do this.
You can try this :
SELECT jsonb_agg(jsonb_build_object
('birth_date', split_part(left(d.data, -1), ',', 3) :: date
,'name', split_part(right(d.data, -1), ',', 1)
,'gender', split_part(d.data, ',', 2)))
FROM your_table AS t
CROSS JOIN LATERAL unnest(t.your_text_column :: text[]) AS d(data)
GROUP BY t
see the test result in dbfiddle.
here is one way:
select Id
, json_agg(json_build_object('name', split_part(jsondata, ',',1) , 'gender', split_part(jsondata, ',',2), 'birth_date', split_part(jsondata, ',' ,3))) json_info
from (
select id
, replace(replace(json_array_elements(replace(replace(info,'{"','["'), '"}','"]')::json) #>> '{}','{',''),'}','') jsondata
from tablename
) t group by id
db<>fiddle here
Related
I have this JSON
"type": "list",
"data": [
{
"id": "5bc7a3396fbc71aaa1f744e3",
"type": "company",
"url": "/companies/5bc7a3396fbc71aaa1f744e3"
},
{
"id": "5b0aa0ac6e378450e980f89a",
"type": "company",
"url": "/companies/5b0aa0ac6e378450e980f89a"
}
],
"url": "/contacts/5802b14755309dc4d75d184d/companies",
"total_count": 2,
"has_more": false
}
I want to dynamically create columns as the number of the companies with their Ids, for example:
company_0
comapny_1
5bc7a3396fbc71aaa1f744e3
5b0aa0ac6e378450e980f89a
Tried to use BigQuery's JSON functions but I didn't get along with it.
Thank you.
Consider below approach
select * except(json) from (
select json, json_extract_scalar(line, '$.id') company, offset
from your_table t, unnest(json_extract_array(json, '$.data')) line with offset
where json_extract_scalar(line, '$.type') = 'company'
)
pivot (any_value(company) company for offset in (0, 1))
if applied to sample data in your question - output is
in postgres 13, I have a Jsonb object and I am able to get only the keys using jsonb_object_keys like this.
SELECT keys from jsonb_object_keys('{
"135": {
"timestamp": 1659010504308,
"priority": 5,
"age": 20
},
"136": {
"timestamp": 1659010504310,
"priority": 2,
"age": 20
},
"137": {
"timestamp": 1659010504312,
"priority": 2,
"age": 20
},
"138": {
"timestamp": 1659010504319,
"priority": 1,
"age": 20
}}') as keys
Now, I want to get the keys which have priority more than 1 and which are ordered by priority and timestamp
I am able to achieve this using this query
select key from (
SELECT data->>'key' key, data->'value' value
FROM
jsonb_path_query(
'{
"135": {
"name": "test1",
"timestamp": 1659010504308,
"priority": 5,
"age": 20
},
"136": {
"name": "test2",
"timestamp": 1659010504310,
"priority": 7,
"age": 20
},
"137": {
"name": "test3",
"timestamp": 1659010504312,
"priority": 5,
"age": 20
},
"138": {
"name": "test4",
"timestamp": 1659010504319,
"priority": 1,
"age": 20
}}'
, '$.keyvalue() ? (#.value.priority > 1)')
as data) as foo, jsonb_to_record(value) x("name" text, "timestamp" decimal,
"priority" int,
"age" int)
order by priority desc, timestamp desc
This doesn't seem to be the efficient way of doing this.
Please share if this can be achieved in a better way (by using jsonb_object_keys !??)
Thanks in advance.
I would first 'normalize' JSON data into a table (the t CTE) and then do a trivial select.
with t (key, priority, ts) as
(
select key, (value ->> 'priority')::integer, value ->> 'timestamp'
from jsonb_each('{
"135": {"timestamp": 1659010504308,"priority": 5,"age": 20},
"136": {"timestamp": 1659010504310,"priority": 2,"age": 20},
"137": {"timestamp": 1659010504312,"priority": 2,"age": 20},
"138": {"timestamp": 1659010504319,"priority": 1,"age": 20}
}')
)
select key
from t
where priority > 1
order by priority, ts;
I have a JSON column (_col0) like below and wanted to update only the 'name' part of json to new value.
{
"id":"1234",
"name":"Demo 1",
"attributes":[
{
"id": "1122",
"name": "affiliate",
"type": "number"
}
],
"behaviors": [
{
"id": "246685",
"name": "Email Send",
"scheduleOption": null,
"defaultTimeFilterEnabled": true,
"schema": []
}
]
}
I wanted to only change value of the outer "name" parameter from 'Demo 1' to 'Demo 2'. The SQL I tried does change the name parameter but makes the rest all to null.
select transform_values(cast(json_parse(_col0) as MAP(varchar, json)) , (k, v) -> if(k='name','Demo 2')) from table1
if has overload with 3 parameters, the 3rd being value for false case, use it to return the current value (you will need to transform either you varchar literal to json or json value to varchar):
-- sample data
WITH dataset (json_str) AS (
VALUES ('{
"id":"1234",
"name":"Demo 1",
"attributes":[
{
"id": "1122",
"name": "affiliate",
"type": "number"
}
],
"behaviors": [
{
"id": "246685",
"name": "Email Send",
"scheduleOption": null,
"defaultTimeFilterEnabled": true,
"schema": []
}
]
}')
)
-- query
select transform_values(
cast(json_parse(json_str) as MAP(varchar, json)),
(k, v)->if(k = 'name', cast('Demo 2' as json), v)
)
from dataset
Output:
_col0
{behaviors=[{"id":"246685","name":"Email Send","scheduleOption":null,"defaultTimeFilterEnabled":true,"schema":[]}], name="Demo 2", attributes=[{"id":"1122","name":"affiliate","type":"number"}], id="1234"}
I have a Json like this in my JsonB column:
{
"emails": [
{
"email": {
"id": "a8399412-165e-4601-824f-a55f631ad471",
"value": "test#gmail.com"
}
},
{
"email": {
"id": "fa09d9a7-a36a-42a4-8627-66b7554ce82e",
"value": "test1#gmail.com"
}
}
],
"Address": [
{
"address": {
"id": "a8399412-165e-4601-824f-a55f631ad471",
"addressLine1": "Line1"
}
},
{
"address": {
"id": "fa09d9a7-a36a-42a4-8627-66b7554ce82e",
"addressLine2": "Line2"
}
}
],
"lastName": {
"id": "bc10a5a9-04ff-4a00-b167-ac3232e5cb89",
"value": "LastName"
},
"firstName": {
"id": "4ccdd400-2586-4a7f-9379-aff4d1f5d9d6",
"value": "FirstName"
}
}
and so on. My requirement to get list of elements as key and value pairs with limit, I did a research tried different functions of postgres and I wrote the below query :
select response.* from my_table t, jsonb_each_text(jsonb_column) as response;
If I do like this I'm getting only the root elements like emails, firstName and lastName, but I want inner elements as well along with their values like below :
Key | value
------- ---------
"email" : {"id": "a8399412-165e-4601-824f-a55f631ad471","value": "test#gmail.com"}
"email" : {"id": "fa09d9a7-a36a-42a4-8627-66b7554ce82e","value": "test1#gmail.com"}
"lastName" : {"id": "bc10a5a9-04ff-4a00-b167-ac3232e5cb89","value": "LastName"}
"firstName" : {"id": "4ccdd400-2586-4a7f-9379-aff4d1f5d9d6","value": "FirstName"}
"address" : {"id": "a8399412-165e-4601-824f-a55f631ad471", "addressLine1": "Line1"}
"address" : {"id": "a8399412-165e-4601-824f-a55f631ad471", "addressLine2": "Line2"}
You can use jsonb_array_elements() function, and combine queries by UNION ALL
SELECT 'email' AS key, je.* ->> 'email' AS value
FROM my_table
CROSS JOIN jsonb_array_elements(jsonb_column->'emails') AS je
UNION ALL
SELECT 'address', ja.* ->> 'address'
FROM my_table
CROSS JOIN jsonb_array_elements(jsonb_column->'Address') AS ja
UNION ALL
SELECT 'lastName', (jsonb_column->'lastName')::text
FROM my_table
UNION ALL
SELECT 'firstName', (jsonb_column->'firstName' )::text
FROM my_table
Demo
I have a select query witch returns me an array_to_json object. I want to filters the results of select based on specifics keys and values.
Here is my actual query:
select jsonarray
from (
SELECT body.id_user,
array_to_json(array_agg(row_to_json(body))) as jsonarray
FROM (
SELECT id_user, name, value
FROM table_1
group by id_user, name, value
) body
group by body.id_user
) as test;
It returns a lot of rows like this:
[{"id_user": 1489, "name": "name 1", "value": "value aaaaaa"}, {"id_user": 1489, "name": "name 2", "value": "value babababab"}]
[{ "id_user": 1490, "name": "name 12", "value": "value aaaaaa" }, { "id_user": 1490, "name": "name 2", "value": "value babababab" }]
[ { "id_user": 1491, "name": "name 13", "value": "value aaaaaa" }, { "id_user": 1491, "name": "name 23", "value": "value uouououo" }]
Well, I want only the rows that have the fields "name": "name 2", "value": "value babababab" into the json... I've tried
select jsonarray->'name'
from (
....
) as test
where jsonarray->>'name'::text = 'name 2';
but it returns nothing. There's another way to query it?
You can check if name 2 is present during the aggregation:
SELECT jsonb_agg(to_jsonb(body)) as jsonarray
FROM (
SELECT DISTINCT id_user, name, value
FROM table_1
) body
group by body.id_user
having bool_or(name = 'name 2') -- those with at least one `name = 'name 2'`
Online example