How to Extract the Fields in Bigquery in Nested JSON - google-bigquery

I have the following BigQuery :
select JSON_EXTRACT_SCALAR(payload, "$.payload") from mytable
It returns this result :
[
{
"productInfo": {
"productId": "123",
"productType": "Dolls"
},
"storefrontPricingList": [
{
"currentPrice": {
"unitValue": {
"currencyAmount": 10,
"currencyUnit": "USD"
},
"currentValue": {
"currencyAmount": 10,
"currencyUnit": "USD"
},
"variableUnitValue": {
"currencyAmount": 10,
"currencyUnit": "USD"
},
"sellValue": {
"currencyAmount": 10,
"currencyUnit": "USD"
},
"type": "EA"
},
"currentPriceType": "OKAY"
}
]
}
]
Now i want to access theses attributes productInfo.productId , currentPrice.unitValue.currencyAmount.
How we can access these elements i tries couple of things but all giving me null :
Like
select JSON_EXTRACT_SCALAR(payload, "$.payload[0].productInfo.productId") from mytable
select JSON_EXTRACT_SCALAR(payload, "$.payload[0].storefrontPricingList[0]. currentPrice. unitValue. currencyAmount") from mytable

Can you try this ?
-- Declaring a bigQuery variable
DECLARE json_data JSON DEFAULT (SELECT PARSE_JSON('{"payload": [{"productInfo": {"productId": "123","productType": "Dolls" },"storefrontPricingList": [{"currentPrice": {"unitValue": {"currencyAmount": 10,"currencyUnit": "USD"},"currentValue": {"currencyAmount": 10,"currencyUnit": "USD"},"variableUnitValue": {"currencyAmount": 10,"currencyUnit": "USD"},"sellValue": {"currencyAmount": 10,"currencyUnit": "USD"},"type": "EA"},"currentPriceType": "OKAY"}]}]}'));
-- Select statement for extraction
select ARRAY(
SELECT JSON_EXTRACT_SCALAR(payload, '$.productInfo.productId') from UNNEST(JSON_EXTRACT_ARRAY(json_data,"$.payload"))payload
)extracted_productID,
ARRAY(
SELECT JSON_EXTRACT_SCALAR(payload, '$.storefrontPricingList[0].currentPrice.unitValue.currencyAmount') from UNNEST(JSON_EXTRACT_ARRAY(json_data,"$.payload"))payload
)extracted_currencyAmount
Used combination of Array function and Json function for BQ.
Output:

Related

Postgresql and jsonb - inserting a key/value into a multi-level array

Very similar to this post, but I struggle to adapt from their solution..
My table : public.challenge, column lines JSONB
My initial JSON in lines :
[
{
"line": 1,
"blocs": [
{
"size": 100,
"name": "abc"
},
{
"size": 100,
"name": "def"
},
{
"size": 100,
"name": "ghi"
}
]
},
{
"line": 2,
"blocs": [
{
"size": 100,
"name": "xyz"
}
]
}
]
Desired update :
[
{
"line": 1,
"blocs": [
{
"size": 100,
"name": "abc",
"type": "regular"
},
{
"size": 100,
"name": "def",
"type": "regular"
},
{
"size": 100,
"name": "ghi",
"type": "regular"
}
]
},
{
"line": 2,
"blocs": [
{
"size": 100,
"name": "xyz",
"type": "regular"
}
]
}
]
So basically I need to add the type key+value in every object of blocs, for each element of the root array.
My unsuccessful attempt looks like this :
UPDATE public.challenge SET lines = jsonb_set(lines, '{}', (
SELECT jsonb_set(line, '{blocs}', (
SELECT jsonb_agg( bloc || '{"type":"regular"}' )
FROM jsonb_array_elements(line->'{blocs}') bloc
))
FROM jsonb_array_elements(lines) line
))
;
(currently it sets the whole column as null, maybe due to jsonb_set(lines, '{}' while my json begins as an array ?)
Thanks!
Use jsonb_array_elements to unnest all the array elements and then add the required json and use jsonb_agg to aggregate it again:
with cte as
(select id,
jsonb_agg(jsonb_set(val1,
'{blocs}',
(select jsonb_agg(arr2 || '{"type": "regular"}')
from jsonb_array_elements(arr1.val1 - >
'blocs') arr2)))
from challenge,
jsonb_array_elements(lines) arr1(val1)
group by 1)
update challenge
set lines = (cte.jsonb_agg)
from cte
where challenge.id = cte.id
DEMO

BigQuery concat nested array json

I have data that looks like
{
"Attributes": [
{
"values": [
{
"value": "20003"
},
{
"value": "30075"
},
{
"value": "40060"
}
],
"name": "price"
}
],
"attr2" : "val"
}
The output I want is concat all the values in the nested json array
price, "20003, 30075, 40060"
I tried some queries but failed to get the correct output.
You can use JSON_EXTRACT_ARRAY and ARRAY_TO_STRING:
WITH test_json AS (
SELECT
'''{
"Attributes": [
{
"values": [
{
"value": "20003"
},
{
"value": "30075"
},
{
"value": "40060"
}
],
"name": "price"
}
],
"attr2" : "val"
}''' AS json_string
),
values_concatenated AS (
SELECT ARRAY_TO_STRING(
ARRAY(
SELECT JSON_VALUE(json_values, '$.value')
FROM UNNEST((SELECT JSON_EXTRACT_ARRAY(json_string, '$.Attributes[0].values') AS json_values FROM test_json)) as json_values
),
', '
) as values
)
SELECT
(select json_value(json_string, '$.Attributes[0].name') from test_json),
(select values from values_concatenated)

How to update value in nested json Postgres

I have following JSON stored in "Info" column
{
"customConfig": {
"isCustomGoods": 1
},
"new_addfields": {
"data": [
{
"val": {
"items": [
{
"Code": "calorie",
"Value": "365.76"
},
{
"Code": "protein",
"Value": "29.02"
},
{
"Code": "fat",
"Value": "23.55"
},
{
"Code": "carbohydrate",
"Value": "6.02"
},
{
"Code": "spirit",
"Value": "1.95"
}
],
"storageConditions": "",
"outQuantity": "100"
},
"parameterType": "Nutrition",
"name": "00000000-0000-0000-0000-000000000001",
"label": "1"
},
{
"name": "b4589168-5235-4ec5-bcc7-07d4431d14d6_Для ресторанов",
"val": "true"
}
]
}
}
I want to update value of nested json
{
"name": "b4589168-5235-4ec5-bcc7-07d4431d14d6_Для ресторанов",
"val": "true"
}
and set "val"to "Yes" str so the result should be like
{
"name": "b4589168-5235-4ec5-bcc7-07d4431d14d6_Для ресторанов",
"val": "Yes"
}
How can i do that ? Assuming that i need to update this value in json for many records in database
Considering you have a constant JSON Structure and a primary key in your table. Idea is to get the exact path of element val having value true (which can be at any index in the array) then replace it with desired value. So you can write your query like below:
with cte as (
select
id,
('{new_addfields,data,'||index-1||',val}')::text[] as json_path
from
test,
jsonb_array_elements(info->'new_addfields'->'data')
with ordinality arr(vals,index)
where
arr.vals->>'val' ilike 'true'
)
update test
set info = jsonb_set(info,cte.json_path,'"Yes"',false)
from cte
where test.id=cte.id;
DEMO
We can use jsonb_set() which is available from Postgres 9.5+
From Docs:
jsonb_set(target jsonb, path text[], new_value jsonb [, create_missing boolean])
Query to update the nested object:
UPDATE temp t
SET info = jsonb_set(t.info,'{new_addfields,data,1,val}', jsonb '"Yes"')
where id = 1;
It can also be used in select query:
SELECT
jsonb_set(t.info,'{new_addfields,data,1,val}', jsonb '"Yes"')
FROM temp t
LIMIT 1;

Take json value in sql without JSON_VALUE

i want to take value (In SQL Server) in json object without JSON_VALUE
The json value :
{{
"Url": "****",
"Token": "",
"Data": {
"role_id": 1001,
"data": {
"stringvalue": [
{
"minage": "21"
},
{
"maxage": "55"
},
{
"primary_identity_file": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/7QCcUGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAIAcAmcAFHpFZEQyY1ZzbGVyRzNrcF8yTjhHHAIoAGJGQk1EMDEwMDBhYzAwMzAwMDAwMjMxMDAwMDQxNzQwMDAwYjQ3YjAwMDBhMTgyMDAwMDliY2EwMDAwMjkyMDAxMDBmODJhMDEwMGFiMzQwMTAwMDgzZTAxMDBjZGM0MDEwMP/iAhxJQ0NfUFJPRklMRQABAQAAAgxsY21zAhAAAG1udHJSR0IgWFlaIA"
}
]
}
}
}}
what i trying to do is to take "primary_identity_file" value
the result should be :
data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/7QCcUGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAIAcAmcAFHpFZEQyY1ZzbGVyRzNrcF8yTjhHHAIoAGJGQk1EMDEwMDBhYzAwMzAwMDAwMjMxMDAwMDQxNzQwMDAwYjQ3YjAwMDBhMTgyMDAwMDliY2EwMDAwMjkyMDAxMDBmODJhMDEwMGFiMzQwMTAwMDgzZTAxMDBjZGM0MDEwMP/iAhxJQ0NfUFJPRklMRQABAQAAAgxsY21zAhAAAG1udHJSR0IgWFlaIA
** NOTE primary_identity_file value is more than 10K character
I'd try something like that:
select substring(vlv3, 1, charindex('"', vlv3)-1) as vlv4
from (
select substring(vlv2, charindex('"', vlv2)+1, len(vlv2)) as vlv3
from (
select substring(vlv, charindex('"primary_identity_file"', vlv)+23, len(vlv)) as vlv2
from test
) as test2
) as test3
You can rewrite in more readable way as stored procedure
Sample fiddle http://sqlfiddle.com/#!18/a122b/7

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?
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'