JSON_MODIFY append $..... already exist instead update,duplicating value - sql

I am trying to add or update using JSON_MODIFY append $.roles in json object roles properties.
But it's seem like instead of updating existing object adding new object.how to solve this not got solution yet.
here is query:
SELECT json_modify(fs1.[Schema], 'append $.roles', json_query(
(
SELECT ar1.rolename AS [role],
ar1.[create] AS [permissions.create],
ar1.[read] AS [permissions.read],
ar1.[update] AS [permissions.update],
ar1.[delete] AS [permissions.delete] FOR json path,
without_array_wrapper ))) AS [Schema]
FROM applicationroles ar1
JOIN commonformsschema fs1
ON ar1.schemaid= fs1.schemaid
Schema column input json:
{
"roles": [
{
"role": "Senior Project Manager",
"permissions": {
"create": true,
"read": true,
"update": true,
"delete": true
}
},
{
"role": "Read",
"permissions": {
"create": false,
"read": true,
"update": true,
"delete": true
}
}
]
}
Current Result:
{
"roles": [
{
"role": "Senior Project Manager",
"permissions": {
"create": true,
"read": true,
"update": true,
"delete": true
}
},
{
"role": "Read",
"permissions": {
"create": false,
"read": true,
"update": true,
"delete": true
}
},
{
"role": "Read",
"permissions": {
"create": false,
"read": true,
"update": false,
"delete": false
}
}
]
}
Expected result:
{
"roles": [
{
"role": "Senior Project Manager",
"permissions": {
"create": true,
"read": true,
"update": true,
"delete": true
}
},
{
"role": "Read",
"permissions": {
"create": false,
"read": true,
"update": false,
"delete": false
}
}
]
}
how to solve this?
thanks.

append is only used if you want to add another object to the array.
If you want to modify the existing object, use the array index:
SELECT json_modify(fs1.[Schema], '$.roles[1]', json_query(
(
SELECT ar1.rolename AS [role],
ar1.[create] AS [permissions.create],
ar1.[read] AS [permissions.read],
ar1.[update] AS [permissions.update],
ar1.[delete] AS [permissions.delete]
FOR json path, without_array_wrapper
))
) AS [Schema]
FROM applicationroles ar1
JOIN commonformsschema fs1
ON ar1.schemaid = fs1.schemaid;
If you don't know whether to add or update, and you are checking based on rolename, instead you can query the current value's index, and update that.
This only works on SQL Server 2017
SELECT json_modify(fs1.[Schema],
ISNULL(N'$.roles[' + j.[key] COLLATE Latin1_General_BIN2 + N']', N'append $.roles'), json_query(
(
SELECT ar1.rolename AS [role],
ar1.[create] AS [permissions.create],
ar1.[read] AS [permissions.read],
ar1.[update] AS [permissions.update],
ar1.[delete] AS [permissions.delete]
FOR json path, without_array_wrapper
))
) AS [Schema]
FROM applicationroles ar1
JOIN commonformsschema fs1
ON ar1.schemaid = fs1.schemaid
OUTER APPLY (
SELECT TOP (1) j.[key]
FROM OPENJSON(fs1.[Schema], '$.roles') j
WHERE JSON_VALUE(j.value, '$.rolename') = ar1.rolename
) j;

Related

jsonb_set not working as expected with nested collections, resulting in null value returned

I am trying to update a nested collection in my Postgres table using json_set, however, my approach is resulting in a collection of null values.
id
payload
row_version
fbfd3b9d-bb20-4c1b-985f-0979890472ec
{ "slots": [ { "bannerXCreatorSettings": { "additionalFields": [ { "label": "test-label", "enabled": true, "mandatory": false, "additionalFieldId": "label", "maxCharacterLimit": 22, "additionalFieldType": "TEXT", "colorHexOptionsList": [] }, { "label": "test-label-2", "enabled": true, "mandatory": false, "additionalFieldId": "label2", "maxCharacterLimit": 55, "additionalFieldType": "TEXT", "colorHexOptionsList": [] } ] } } ]}
1
I have the following json payload stored in my table:
{
"slots": [
{
"bannerXCreatorSettings": {
"additionalFields": [
{
"label": "test-label",
"enabled": true,
"mandatory": false,
"additionalFieldId": "label",
"maxCharacterLimit": 22,
"additionalFieldType": "TEXT",
"colorHexOptionsList": []
},
{
"label": "test-label-2",
"enabled": true,
"mandatory": false,
"additionalFieldId": "label2",
"maxCharacterLimit": 55,
"additionalFieldType": "TEXT",
"colorHexOptionsList": []
}
]
}
}
]
}
Within the additionalFields collections, I want to add selectOptions. Like this:
{
"slots": [
{
"bannerXCreatorSettings": {
"additionalFields": [
{
"label": "test-label",
"enabled": true,
"mandatory": false,
"additionalFieldId": "label",
"maxCharacterLimit": 22,
"additionalFieldType": "TEXT",
"colorHexOptionsList": [],
"selectOptions": [] <-- new field
},
{
"label": "test-label-2",
"enabled": true,
"mandatory": false,
"additionalFieldId": "label2",
"maxCharacterLimit": 55,
"additionalFieldType": "TEXT",
"colorHexOptionsList": [],
"selectOptions": [] <-- new field
}
]
}
}
]
}
I have written the following SQL to try update the JSON payload within my table:
select
id,
payload,
row_version,
jsonb_set(
payload,
'{slots}',
(select
jsonb_agg(
jsonb_set(
slot_elem,
'{bannerXCreatorSettings}',
jsonb_set(
slot_elem -> 'bannerXCreatorSettings',
'{additionalFields}',
(
select
jsonb_agg(
jsonb_set(
field_element,
'{selectOptions}',
jsonb_build_array()))
from jsonb_array_elements(
slot_elem -> '{bannerXCreatorSettings}' #>'{additionalFields}') WITH ORDINALITY a_t(field_element, idx_1))
)
)
)
FROM
jsonb_array_elements(
payload #> '{slots}') WITH ORDINALITY t(slot_elem, idx))) as payload_update
My understanding of SQL is limited, however, I feel as though this should work. Unfortunally the above query results in the following:
{
"slots": [
null,
null
]
}

Extract array from varchar in PrestoSQL

I have a VARCHAR field like this:
[
{
"config": 0,
"type": "0
},
{
"config": x,
"type": "1"
},
{
"config": "",
"type": ""
},
{
"config": [
{
"address": {},
"category": "",
"merchant": {
"data": [
10,12,23
],
"file": 0
},
"range_id": 1,
"shop_id_info": null
}
],
"type": "new"
}
]
And I need to extract merchant data from this. Desirable output is:
10
12
23
Please advise. I keep getting Cannot cast VARCHAR to array/unnest type VARCHAR
You can try using json path $.*.config.*.merchant.data.* but if it does not work for you (as for me in Athena version, where arrays in json path are not supported well) you can cast your json to ARRAY(JSON) and do some manipultaions from there (needed to fix your JSON a little bit):
Test data:
WITH dataset AS (
SELECT * FROM (VALUES
(JSON '[
{
"config": {},
"type": "0"
},
{
"config": "x",
"type": "1"
},
{
"config": "",
"type": ""
},
{
"config": [
{
"address": {},
"category": "",
"merchant": {
"data": [
10,12,23
],
"file": 0
},
"range_id": 1,
"shop_id_info": null
}
],
"type": "new"
}
]')
) AS t (json_value))
And query:
SELECT flatten(
transform(
flatten(
transform(
CAST(json_value AS ARRAY(JSON))
, json_object -> try(CAST(json_extract(json_object, '$.config') AS ARRAY(JSON))))),
json_config -> CAST(json_extract(json_config, '$.merchant.data') as ARRAY(INTEGER))))
FROM dataset
Which will give you array of numbers:
_col0
[10, 12, 23]
And from there you can continue with unnest and so on if needed.

How to replace a string value with an object inside a column the contains json object

I'm using PostgreSQL and I have a table that has a text column named additional_info.
This columns on this table currently contains a JSON object as below:
{
"dbServiceAccount": {
"aggregationMode": "DbServiceAccount",
"destinationIp": "10.10.10.29",
"db": "xe",
"dbType": "Oracle",
"dbUser": "system"
},
"clients": [{
"user": "user5"
}, {
"user": "user4"
}]
}
I want to replace the value of the key 'dbServiceAccount' with an object.
The object should have a key 'name' that holds the original string value, like below:
{
"dbServiceAccount": {
"aggregationMode": {
"name": "DbServiceAccount"
},
"destinationIp": "10.10.10.29",
"db": "xe",
"dbType": "Oracle",
"dbUser": "system"
},
"clients": [{
"user": "user5"
}, {
"user": "user4"
}]
}
How can I do this?
This can be done using jsonb_set.
with t(oldj) as
(
select '{
"dbServiceAccount": {
"aggregationMode": "DbServiceAccount",
"destinationIp": "10.10.10.29",
"db": "xe",
"dbType": "Oracle",
"dbUser": "system"
},
"clients": [{"user": "user5"}, {"user": "user4"}]
}'::jsonb
) -- the original JSONB object
select jsonb_set
(
oldj,
array['dbServiceAccount', 'aggregationMode'],
jsonb_build_object('name', oldj -> 'dbServiceAccount' ->> 'aggregationMode')
) as newj -- the resulting JSONB object
from t;
/* result:
{
"clients": [
{
"user": "user5"
},
{
"user": "user4"
}
],
"dbServiceAccount": {
"db": "xe",
"dbType": "Oracle",
"dbUser": "system",
"destinationIp": "10.10.10.29",
"aggregationMode": {
"name": "DbServiceAccount"
}
}
}
*/
I finally solved this:
WITH aggregationMode AS (
select additional_info::json ->'dbServiceAccount' -> 'aggregationMode' as aggregationMode from incidents."groups" g where id in ('3085875798')
)
UPDATE
incidents."groups" g
SET
additional_info = REPLACE(additional_info,CONCAT ('"aggregationMode":"', (select * from aggregationMode), '"'),
CONCAT ('"aggregationMode": {"name": "', (select * from aggregationMode), '"}'))
where id = '111'

Postgres inner json update

{
"travel": {
"arrival": {
"time": "2020-09-03T10:05:00.000Z",
"type": "Contract",
"driver": "saman",
"provider": "ideal",
"vehicleno": null
},
"departure": {
"time": "2020-09-03 16:55",
"type": "Contract",
"driver": "saman",
"provider": null,
"vehicleno": null
}
},
"serviceend": "2020-09-03T11:15:00.000Z",
"costsheetno": "AA 67856",
"servicestart": "2020-09-03T10:10:00.000Z"
}
How to set costsheet->'travel'->'departure'->'time'=null ?
You can use jsonb_set() like that:
jsonb_set(costsheet, '{travel,departure,time}', 'null')

POSTGRESQL query to extract attributes in JSON

I have the below JSON in a particular DB column. I need a query to extract fields stored within the savings rate(to and from).
{
"data": [
{
"data": {
"intro_visited": {
"portfolio_detail_investment_journey": true,
"dashboard_investments": true,
"portfolio_list_updates": true,
"portfolio_detail_invested": true,
"portfolio_list_offering": true,
"dashboard_more_bottom_bar": true
}
},
"type": "user_properties",
"schema_version": "1"
},
{
"data": {
"savings_info": {
"remind_at": 1583475493291,
"age": 100,
"savings_rate": {
"to": "20",
"from": "4"
},
"recommendation": {
"offering_name": "Emergency Fund",
"amount": "1,11,111",
"offering_status": "not_invested",
"ideal_amount": "1,11,111",
"offering_code": "liquid"
}
}
},
"type": "savings_info",
"schema_version": "1"
}
]
}
To get the "To"
$..data.savings_info.savings_rate.to
To get the "From"
$..data.savings_info.savings_rate.from
This script works
SELECT
<column> ->'data'->2->'data'->'savings_info'->'savings_rate'->>'to' AS to_rate
from <table>