Migrate from an array of strings to an array of objects (JSONB) - database

I have an array of strings in a jsonb column in a postgres DB, which I'd like to migrate to an array of objects with 2 fields. So, turn this:
"Umbrella": [
"green|bubbles",
"blue|clouds"
],
into this:
"items": {
"umbrella": [
{
"color": "green",
"pattern": "bubbles"
},
{
"color": "blue",
"pattern": "clouds"
}
]
}
I managed to migrate the first value of the array, but I don't know how to implement a "foreach" to do this for all items.
What I tried (public.metadata is the table and metadata is the jsonb column):
update public.metadata set metadata = jsonb_set(metadata, '{items}', '{}');
update public.metadata set metadata = jsonb_set(metadata, '{items, umbrella}', '[]');
update public.metadata set metadata = jsonb_insert(metadata, '{items, umbrella, 0}', '{"color":"1", "pattern":"2"}');
update public.metadata
set metadata = jsonb_set(
metadata,
'{items, umbrella, 0, color}',
to_jsonb(split_part(metadata -> 'Umbrella' ->> 0, '|', 1))
);
update public.metadata
set metadata = jsonb_set(
metadata,
'{items, umbrella, 0, pattern}',
to_jsonb(split_part(metadata -> 'Umbrella' ->> 0, '|', 2))
);
I thought maybe this could lead me to the final solution, but I'm stuck.

I manage to solve it like this:
-- from array of strings to array of objects
update public.metadata set metadata = jsonb_set(metadata #- '{Umbrella}', '{items, umbrella}',
(select jsonb_agg(
jsonb_build_object(
'color', (split_part(x::text, '|', 1)),
'pattern', (split_part(x::text, '|', 2))
)
) from public.metadata, jsonb_array_elements_text(metadata.metadata->'Umbrella') x)
) where metadata->'Umbrella' is not null and metadata -> 'Umbrella' != '[]'::jsonb;;

Related

I need to get the duplicate data in column parenthesis

UPDATE tab s
SET s.DATA = json_transform(DATA, REPLACE '$.dataFilterDefn.columns[1]' = (SELECT JSON_ARRAYAGG(JSON FORMAT JSON RETURNING CLOB)
FROM
(SELECT JSON
FROM
(SELECT j.json || ',' || JSON AS json
FROM tab d
CROSS APPLY JSON_TABLE(d.tab, '$.dataFilterDefn.columns[1]' COLUMNS(json CLOB FORMAT JSON PATH '$')) j
WHERE d.UID = 252))));
The data look like this:
"columns":[
{
"label":"Subcategory",
"aggFn":"NONE",
"datasetId":"ADVENTURE_WORKS",
"fieldName":"SUB_CAT",
"id":"FILTER-1"
}
]
My expectation:
"columns":[
{
"label":"Subcategory",
"aggFn":"NONE",
"datasetId":"ADVENTURE_WORKS",
"fieldName":"SUB_CAT",
"id":"FILTER-1"
},
{
"label":"Subcategory",
"aggFn":"NONE",
"datasetId":"ADVENTURE_WORKS",
"fieldName":"SUB_CAT",
"id":"FILTER-1"
}
]
I want the columns data should duplicate.The columns value will be different.It"ll not be the same. I need to update the column values dynamically..It should not be hardcoded. How can I achieve this in json using Oracle version 19c?
Using json_transform you can append items to an array. Using json_query you can extract the first element of the array.
So you can do something like this:
with rws as (
select '{ "columns":[
{
"label":"Subcategory",
"aggFn":"NONE",
"datasetId":"ADVENTURE_WORKS",
"fieldName":"SUB_CAT",
"id":"ART-DATA-FILTER-1"
}
] }' jdata
from dual
)
select json_transform (
jdata,
append '$.columns' = json_query ( jdata, '$.columns[0]' )
returning varchar2 pretty
)
from rws r;
{
"columns" :
[
{
"label" : "Subcategory",
"aggFn" : "NONE",
"datasetId" : "ADVENTURE_WORKS",
"fieldName" : "SUB_CAT",
"id" : "ART-DATA-FILTER-1"
},
{
"label" : "Subcategory",
"aggFn" : "NONE",
"datasetId" : "ADVENTURE_WORKS",
"fieldName" : "SUB_CAT",
"id" : "ART-DATA-FILTER-1"
}
]
}
Note that json_transform was only added in a recent release update, so ensure your 19c version is fully patched and up-to-date.

How to Update JSON data in an array

I have a JSON Column in my table that has an array of JSON Data like this:
save_data
[
{"option_id": 20000, "question_id": 10000},
{"option_id": 20001, "question_id": 10001},
{"option_id": 20002, "question_id": 10002}
]
I can get the record using this:
$save_data = DB::table('save_state')
->whereJsonContains('save_data', [["option_id" => 20002]])
->get();
But now what I want is to update only the option_id value of the element which has the question_id that I want, for example:
change option_id value to "20003" of question_id = "10002"
I have tried this but it still doesn't work.
$save_data = DB::table('save_state')
->whereJsonContains('save_data', [["option_id" => 20002]])
->update(['save_data->option_id' => [20003]]);

Search comparing and searching for strings in a varient table, trouble with correct construct for varient type

So I am following the example in the documentation here as I am trying to compare the json strings that I have uploaded from the tutorial, but am having troubles searching the variant type I uploaded my json file into.
So for the basic understanding I tried:
USE DATABASE MYDB;
USE WAREHOUSE MYWH;
create table demonstration1 (
id integer,
array1 array,
variant1 variant,
object1 object
);
insert into demonstration1 (id, array1, variant1, object1)
select
1,
array_construct(1, 2, 3),
parse_json(' { "key1": "value1", "key2": "value2" } '),
parse_json(' { "outer_key1": { "inner_key1A": "1a", "inner_key1B": "1b" }, '
||
' "outer_key2": { "inner_key2": 2 } } ')
;
insert into demonstration1 (id, array1, variant1, object1)
select
1,
array_construct(1, 2, 3, null),
parse_json(' { "key1": "value1", "key2": NULL } '),
parse_json(' { "outer_key1": { "inner_key1A": "1a", "inner_key1B": NULL }, '
||
' "outer_key2": { "inner_key2": 2 } '
||
' } ')
;
select variant1 from demonstration1
where variant1 contains('value');
error was that it did not recognize contains:
SQL compilation error: syntax error line 2 at position 17 unexpected 'contains'.
This did not work either when I tried to use Array_contains:
ARRAY_CONTAINS('value'::variant, array_construct(variant1)) from demonstration1;
What should I be trying?
The syntax for contains is a bit different. Try this instead:
select variant1 from demonstration1 where contains(variant1, 'value2');

Indexing and querying JSON array

I have JSON values like this stored in a table:
{
"properties":[
{
"address":{
"value":"A3",
"name":"",
"prop":"",
"path":[
"RealOptionsList9293"
],
"type":"local"
},
"value":{
"type":11,
"value":"portland"
},
"dependents":[
],
"save":true
}
]
}
I'd like to index on address.value and value.value so that I can query on them. MSDN examples are for basic property using computed column. It does not cover indexing an array. Is indexing possible on array? Any example will be helpful.
I'd like to query for rows with:
JSON_VALUE(mycolumn, '$.properties[*].address.value') = 'A3'
AND JSON_VALUE(mycolumn, $.properties[*].value.value) = 'portland'
I don't see [*] syntax. Should I use OPENJSON() instead? If I use it, should I use a materialized view?
If you want to query a JSON array, OPENJSON() is more appropriate:
Table:
CREATE TABLE #Data (
JsonData nvarchar(max)
)
INSERT INTo #Data (JsonData)
VALUES (N'{
"properties":[
{
"address":{
"value":"A3",
"name":"",
"prop":"",
"path":[
"RealOptionsList9293"
],
"type":"local"
},
"value":{
"type":11,
"value":"portland"
},
"dependents":[
],
"save":true
},
{
"address":{
"value":"A4",
"name":"",
"prop":"",
"path":[
"RealOptionsList9293"
],
"type":"local"
},
"value":{
"type":11,
"value":"portland"
},
"dependents":[
],
"save":true
}
]
}')
Statement:
SELECT d.*
FROM #Data d
CROSS APPLY OPENJSON(d.JsonData, '$.properties') WITH (
AddressValue nvarchar(1000) '$.address.value',
ValueValue nvarchar(1000) '$.value.value'
) j
WHERE j.AddressValue = 'A3' AND ValueValue = 'portland'
When you want to query JSON arrays or objects you should use JSON_QUERY which is designed to work with that. JSON_VALUE is designed to return a scalar, thus, if you use JSON_VALUE with address, value or even dependents (in your JSON), it'll always returns null. But if you use it with save, it'll return its value.
So, what you need to do is something like this :
SELECT
JSON_VALUE([Address],'$.value')
FROM (
SELECT
JSON_QUERY(#json,'$.properties[0].address') AS [Address]
, JSON_QUERY(#json,'$.properties[0].value') AS [Value]
, JSON_QUERY(#json,'$.properties[0].dependents') AS [dependents]
) arrays

Convert array of arrays to array of hash

I have following array of arrays in Perl that are getting as multiple rows in database.
$arrayref = [
[ 1, "name1", "name2" ],
[ 2, "name3", undef ],
[ 3, "name5", "name6" ],
[ 4, "name10", undef ],
];
I want to make this as an array of hashes like this
my #array = (
{ id => 1, name => "name1", l_name => "name2" },
{ id => 2, name => "name3", l_name => undef },
{ id => 3, name => "name5", l_name => "name6" },
{ id => 4, name => "name10", l_name => undef },
);
You can use map {} to transform array references to hash references,
my #cols = qw(id name l_name);
my #array = map { my %h; #h{#cols} = #$_; \%h } #$arrayref;
or
use List::MoreUtils qw( zip );
my #cols = qw(id name l_name);
my #array = zip(\#cols, #$arrayref);
I have following array of arrays in Perl that are getting as multiple rows in database
You are presumably calling
$sth->fetchall_arrayref();
If instead you use an empty anonymous hash as the first parameter
$sth->fetchall_arrayref( {} );
then DBI will return the data in the format you want as an array of hashes
The DBI documentation describes it here
If $slice is a hash reference, fetchall_arrayref fetches each row as a hash reference. If the $slice hash is empty then the keys in the hashes have whatever name lettercase is returned by default. (See FetchHashKeyName attribute.) If the $slice hash is not empty, then it is used as a slice to select individual columns by name. The values of the hash should be set to 1. The key names of the returned hashes match the letter case of the names in the parameter hash, regardless of the FetchHashKeyName attribute.
For example, to fetch all fields of every row as a hash ref:
$tbl_ary_ref = $sth->fetchall_arrayref({});

Resources