Update data of array json - sql

MyTable
id | data
___________
1 |[{"Session1": "", "DeviceId1": ""}, {"Session2": "", "DeviceId2": ""}]
I want update data and set Session1 equal to xxx and DevicceId1 eaqual to yyy
I write this query but this not worked
update MyTable data=jsonb_set(data, '{Session1}', 'xxx',true)
How can update value of array of json in PostgreSQL?

data is a json array, so the path to Session1 needs to be {0,Session1}, similarly {0,DeviceId1} for DeviceId1
Which would make the update statement:
UPDATE "MyTable"
SET "data" = jsonb_set(jsonb_set(data, '{0,Session1}', '"xxx"', true), '{0,DeviceId1}', '"yyy"', true)
WHERE id = 1

You can use a json array index (starting from 0) as a path:
update my_table
set data = jsonb_set(data, '{0}', '{"Session1": "xxx", "DeviceId1": "yyy"}')
where id = 1
returning *;
id | data
----+------------------------------------------------------------------------------
1 | [{"Session1": "xxx", "DeviceId1": "yyy"}, {"Session2": "", "DeviceId2": ""}]
(1 row)

Related

Update column with the same value apart from an object removed in column in Sqlite

I want to remove an object from a json column in Sqlite and I can't make it work. The json column contains a nested object, has the following type:
{
a: number;
pair: {
field1: string;
field2: string;
}[]
}
I want to update the column "ArrayColumn" with the same values but remove the object that has field1 equal to "0" and field2 equal to "1" . Every row contains the "pair" array, but not all the "pair" arrays in ArrayColumn contain this value ({"field1":"0", "field2":"1"})
I have the following structure:
Id| ArrayColumn
--------------------------------------------------------------------------------------------
1 | { "a":1, "pair":[{"field1":"0", "field2":"1"},{"field1":"C", "field2":"D"},{"field1":"E", "field2":"F"}] }
2 | { "a":5, "pair":[{"field1":"C", "field2":"D"},{"field1":"E", "field2":"F"}] }
3 | { "a":8, "pair":[{"field1":"G", "field2":"G"},{"field1":"0", "field2":"1"},{"field1":"A", "field2":"A"}] }
4 | { "a":1, "pair":[{"field1":"F", "field2":"T"},{"field1":"C", "field2":"D"},{"field1":"0", "field2":"1"}] }
5 | { "a":1, "pair":[{"field1":"A", "field2":"B"}] }
After updating the rows, the values would be:
Id| ArrayColumn
--------------------------------------------------------------------------------------------
1 | { "a":1, "pair":[{"field1":"C", "field2":"D"},{"field1":"E", "field2":"F"}] }
2 | { "a":5, "pair":[{"field1":"C", "field2":"D"},{"field1":"E", "field2":"F"}] }
3 | { "a":8, "pair":[{"field1":"G", "field2":"G"},{"field1":"A", "field2":"A"}] }
4 | { "a":1, "pair":[{"field1":"F", "field2":"T"},{"field1":"C", "field2":"D"}] }
5 | { "a":1, "pair":[{"field1":"A", "field2":"B"}] }
I tried with JSON_TREE but can't make it work.
I was thinking that the first step would be to select all the rows that contain that value, I retreived them using these 2 ways:
With LIKE operator searching for the stringified form:
select Id, json_extract(json(par), '$.pair') as pair from Table pair like '%{"field1":"0","field2":"1"}%'
Using json_tree
select Id, value from Table, json_tree(Table.ArrayColumn, '$.pair' ) where json_extract(value, '$.field1' ) = '0' AND json_extract(value, '$.field2' ) = '1'
I tried using json_remove with this small example but no luck:
SELECT json_remove('[{"field1":"1","field2":"0"},{"field1":"A","field2":"B"}]', '${"field1":"1","field2":"0"}' )
I tried using json_remove but had no luck.
Thank you
For this sample data the simplest way to do this is to treat the json column as a string and use string functions to remove the value that you want:
UPDATE tablename
SET ArrayColumn = REPLACE(REPLACE(REPLACE(ArrayColumn, ']', ',]'), '{"field1":"0", "field2":"1"},', ''), ',]', ']')
WHERE ArrayColumn LIKE '%{"field1":"0", "field2":"1"}%';
See the demo.

Migrating data from jsonb to integer[] SQL

I have jsonb field(data) in Postgresql with a structure like:
{ "id" => { "some_key" => [1, 2, 3] } }
I need to migrate the value to a different field.
t.jsonb "data"
t.integer "portals", default: [], array: true
When I'm trying to do like this:
UPDATE table_name
SET portals = ARRAY[data -> '1' ->> 'portals']
WHERE id = 287766
It raises an error:
Caused by PG::DatatypeMismatch: ERROR: column "portals" is of type integer[] but expression is of type text[]
Here is one way to do it. But if you search the site, as you should had to do, you get more.
Schema
create table t (
data jsonb
);
insert into t values ('{"1" : { "k1" : [1,2,3,5]} }');
insert into t values ('{"2" : { "k2" : [4,5,6,7]} }');
create table i (
id int,
v int[]
)
Some tests
select data -> '1' -> 'k1'
from t
where data ? '1'
;
insert into i values(1,ARRAY[1,2,3]);
update i
set v = (select replace(replace(data -> '1' ->> 'k1', '[', '{'), ']', '}')::int[] from t where data ? '1')
where id = 1;
select * from i;
The above gets array as a text, as you did. After that, just some text replacements to cast the text to an integer array literal.
DB Fiddle

How to transform jsonb object to an array of objects?

From this:
"data": {
"media_object_uuid": ["5171167e-c109-4926-9606-5212ee250e2f"]
}
to this:
"data": {
"media_object":[{"media_object_uuid": "5171167e-c109-4926-9606-5212ee250e2f"]
}
In words, I want to extract the first value of this array and set it on the new field media_object_uuid inside media_object. My approach to resolve this was:
update demo_test set data = jsonb_set(data,'{media_object_uuid}',('{"media_object": { "media_object_uuid":' || (data->"media_object_uuid"[0])::text || '}}'));
But I have in return media_object_uuid column doesn't exist
I think you need to call data->"media_object_uuid" as data->'media_oject_uuid', since in Postgres, double-quotes are used to refer to column/entity names (unless they are first encapsulated in single-quotes):
edb=# create table abc (data jsonb);
CREATE TABLE
edb=# insert into abc values ('{
edb'# "media_object_uuid": ["5171167e-c109-4926-9606-5212ee250e2f"]
edb'# }');
INSERT 0 1
edb=# select ('{"media_object": [{ "media_object_uuid":' || (data->'media_object_uuid')::text || '}]}') from abc;
?column?
-------------------------------------------------------------------------------------
{"media_object": [{ "media_object_uuid":["5171167e-c109-4926-9606-5212ee250e2f"]}]}
(1 row)
edb=# update abc set data = jsonb_set(data,'{media_object_uuid}', ('{"media_object": [{ "media_object_uuid":' || (data->'media_object_uuid')::text || '}]}')::jsonb);
UPDATE 1
edb=# select * from abc;
data
------------------------------------------------------------------------------------------------------------
{"media_object_uuid": {"media_object": [{"media_object_uuid": ["5171167e-c109-4926-9606-5212ee250e2f"]}]}}
(1 row)

How to automate a field mapping using a table in snowflake

I have one column table in my snowflake database that contain a JSON mapping structure as following
ColumnMappings : {"Field Mapping": "blank=Blank,E=East,N=North,"}
How to write a query that if I feed the Field Mapping a value of E I will get East or if the value if N I will get North so on and so forth without hard coding the value in the query like what CASE statement provides.
You really want your mapping in this JSON form:
{
"blank" : "Blank",
"E" : "East",
"N" : "North"
}
You can achieve that in Snowflake e.g. with a simple JS UDF:
create or replace table x(cm variant) as
select parse_json(*) from values('{"fm": "blank=Blank,E=East,N=North,"}');
create or replace function mysplit(s string)
returns variant
language javascript
as $$
res = S
.split(",")
.reduce(
(acc,val) => {
var vals = val.split("=");
acc[vals[0]] = vals[1];
return acc;
},
{});
return res;
$$;
select cm:fm, mysplit(cm:fm) from x;
-------------------------------+--------------------+
CM:FM | MYSPLIT(CM:FM) |
-------------------------------+--------------------+
"blank=Blank,E=East,N=North," | { |
| "E": "East", |
| "N": "North", |
| "blank": "Blank" |
| } |
-------------------------------+--------------------+
And then you can simply extract values by key with GET, e.g.
select cm:fm, get(mysplit(cm:fm), 'E') from x;
-------------------------------+--------------------------+
CM:FM | GET(MYSPLIT(CM:FM), 'E') |
-------------------------------+--------------------------+
"blank=Blank,E=East,N=North," | "East" |
-------------------------------+--------------------------+
For performance, you might want to make sure you call mysplit only once per value in your mapping table, or even pre-materialize it.

Save array in DB when checked more than one checkbox

I have a problem greatest!! I guess that really want Array, look my console when I checked just one:
{"value_solve"=>["", "", "333", ""], "contract_number"=>["33"]}
-----
SQL (317.5ms) UPDATE "authorizations" SET "value_solve" = '', "situation" = 2 WHERE "authorizations"."contract_number" = ? [["contract_number", "33"]]
After, when I checked just one, the first:
{"value_solve"=>["111", "", "", ""], "contract_number"=>["11"]}
-----
SQL (317.5ms) UPDATE "authorizations" SET "value_solve" = '111 ', "situation" = 2 WHERE "authorizations"."contract_number" = ? [["contract_number", "11"]]
And, for last, when I just more then one:
{"contract_number"=>["11", "44"], "value_solve"=>["111", "", "", "444"]}
-----
SQL (297.7ms) UPDATE "authorizations" SET "value_solve" = '111', "situation" = 2 WHERE "authorizations"."contract_number" = ? [["contract_number", "11"]]
SQL (121.9ms) UPDATE "authorizations" SET "value_solve" = '', "situation" = 2 WHERE "authorizations"."contract_number" = ? [["contract_number", "44"]]
And this is my controller:
#selected_ids = params[:authorization][:contract_number]
#authorizations = Authorization.where("contract_number in (?)", #selected_ids)
auth_params = params[:authorization]
auth_params[:contract_number].zip(auth_params[:value_solve]).each do |contract_number, value_solve|
Authorization.where(contract_number: contract_number).update_all(value_solve: value_solve, situation: 2)
end
Just save the first value on DB, how I can save more then one value? Thanks!
As I understood, you want the contract_number with id 44 to be “associated” with value_solve == "444". If this is correct, you should remove blanks from your value_solve array:
auth_params[:contract_number].zip(auth_params[:value_solve].reject(&:blank?))...
Now 44 is being updated with the second element of value_solve, which is apparently an empty string.
See Array#zip for more details.