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

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
]
}

Related

Parsing Dynamic response in Karate

I want to verify the value of "RequestedName" in the following response, where the keys for different drugs is dynamic:
{
"requestId": "c826bee1-610e-4dee-b998-1fe4f8c15a1b",
"requestSource": "",
"responseSource": "client",
"status": 200,
"responseCodes": [
{
"code": "S00001",
"message": "Success.",
"params": {
"entity": ""
}
}
],
"context": null,
"payload": {
"0113ccf86ba79b698b8e7a8fb9effc4b": {
"RequestedName": "paracetamol",
"SearchKey": "0113ccf86ba79b698b8e7a8fb9effc4b",
"Name": "Genexa Acetaminophen Extra Strength",
"PrescribableName": "",
"ProductCodes": [
"69676-0059"
],
"DosageForm": "Tablet, coated",
"Route": "Oral",
"Approved": false,
"UnApproved": false,
"Generic": false,
"Allergen": false,
"Vaccine": false,
"Strength": {
"Number": "500",
"Unit": "mg/1"
},
"Purposes": {},
"SideEffects": {}
},
"0349fa4ea29da419c46745bc7e2a6c07": {
"RequestedName": "paracetamol",
"SearchKey": "0349fa4ea29da419c46745bc7e2a6c07",
"Name": "Pain Reliever",
"PrescribableName": "",
"ProductCodes": [
"70677-0168"
],
"DosageForm": "Tablet, extended release",
"Route": "Oral",
"Approved": true,
"UnApproved": false,
"Generic": true,
"Allergen": false,
"Vaccine": false,
"Strength": {
"Number": "650",
"Unit": "mg/1"
},
"Purposes": {},
"SideEffects": {}
},
"060cfbde5d82d947c56aac304c136fd3": {
"RequestedName": "paracetamol",
"SearchKey": "060cfbde5d82d947c56aac304c136fd3",
"Name": "Betr Pain Relief",
"PrescribableName": "Acetaminophen 500 mg Oral Tablet",
"ProductCodes": [
"80267-0484"
],
"DosageForm": "Tablet",
"Route": "Oral",
"Approved": false,
"UnApproved": false,
"Generic": false,
"Allergen": false,
"Vaccine": false,
"Strength": {
"Number": "500",
"Unit": "mg/1"
},
"Purposes": {},
"SideEffects": {}
},
"0950fcbac262c1c1d3a9e6630615a5f9": {
"RequestedName": "paracetamol",
"SearchKey": "0950fcbac262c1c1d3a9e6630615a5f9",
"Name": "Acetaminophen",
I tired this:
* def list = []
* def fun = function(k, v){ karate.appendTo('list', { key: k, val: v } )}
* karate.forEach(response, fun)
* def keys = $list[?(#.val.payload.RequestedName==drugName)].key
but not working, getting error as below:
def keys = $list[?(#.val.payload.RequestedName==drugName)].key
Failed to parse filter: [?(#.val.payload.RequestedName==drugName)], error on position: 32, char: d
testsuite/GetDrugs.feature:20
Here is the approach you can use:
* def response =
"""
{
dynamicKey1: {
fixedKey: 'fixedValue1',
dataKey: 'dataValue2'
},
dynamicKey2: {
fixedKey: 'fixedValue2',
dataKey: 'dataValue2'
}
}
"""
* def keys = []
* def fun = function(k, v){ if (v.fixedKey == 'fixedValue2') keys.push(k) }
* karate.forEach(response, fun)
* match keys == ['dynamicKey2']

Unable to access data in Postgres query where clause

I am dealing with the following JSON in a Postgres database column called steps in a table called tCampaign :
[
{
"name":"Step 1",
"stepReference":"01e9f7c0-bc79-11eb-ab6f-2fa1cb676e38",
"rewardConditions": [
{
"conditionDefinitions": [
{
"instanceId":"01805260-0818-4e99-e5b1-5820d1b133cd",
"type":"registration",
"properties": null,
"name": "Registration"
},
{
"instanceId":"01e115c3-5e56-437a-5d13-6c04281e9588",
"type":"optIn",
"properties": null,
"name":"Opt In"
}
],
"rewardDefinitions":[
{
"instanceId":"01c82190-1d56-44f9-474a-513732302e28",
"type":"sportsReward",
"properties": {"activation": {"type": "onReward"}, "betFlavour": "SPORTS", "channels": ["__use_campaign_restrictions__"], "expiry": {"offset": {"days": "02", "hours": "00", "minutes": "00", "seconds": "00"}, "type": "relative"}, "inRunning": "-", "maxReward": {"USD": "1"}, "minimumOdds": "", "oddsInput": {"minimumOdds": {"american": "", "european": ""}}, "retail": "offBetBuild", "returnStakeOnPayout": "false"},
"name":"Freebet",
"calculator":{"type":"fixed","value":"100"}
}
]
}
]
},
{
"name" : "Step 2",
"stepReference" : "01daa4a0-bc79-11eb-ab6f-2fa1cb676e38",
"rewardConditions": [
{
"conditionDefinitions": [
{
"instanceId" : "01fb15ae-01d0-49e1-966a-8ff438e9a191",
"type" : "genericSportsBet",
"properties" : {"betFlavour": "SPORTS", "betTrackEventThreshold": "10", "betTypes": [ "SGL" ], "builderBetOption": "ALL", "channels": [ "__use_campaign_restrictions__" ], "currencyThresholdMap": { "USD": "1" }, "eventHierarchySelection": { "categories": [], "classes": [], "events": [], "marketTemplates": [], "markets": [ "5824" ], "retrobetEventIds": [ "1200" ], "selections": [], "selectionsMarket": [], "types": [] }, "eventHierarchySelectionUI": { "markets": [ { "id": 5824, "mapping": [], "name": "Match Result", "parentId": 1200, "parentParentId": 5, "path": [ "Category: |England|", "Class: |England Premier League|", "Type: |GK Team K| |vs| |GK Team L|" ], "selectionMapper": false, "settled": "N", "startTime": "2021-05-31 11:15:00", "status": "A" } ] }, "inRunning": "-", "legTypes": [ "WIN" ], "metOnSettlement": false, "minOdds": "", "oddsInput": { "minOdds": { "american": "", "european": "" } }, "priceTypes": [ "LP" ]},
"name" : "Sports Bet"
}
],
"rewardDefinitions":[
{
"instanceId" : "0110eb70-44f9-4d57-40bb-09ff4169136c",
"type" : "sportsReward",
"properties" : {"activation": {"type": "onReward"}, "betFlavour": "SPORTS", "channels": ["__use_campaign_restrictions__"], "expiry": {"offset": {"days": "02", "hours": "00", "minutes": "00", "seconds": "00"}, "type": "relative"}, "inRunning": "-", "maxReward": {"USD": "2"}, "minimumOdds": "", "oddsInput": {"minimumOdds": {"american": "", "european": ""}}, "retail": "offBetBuild", "returnStakeOnPayout": "false"},
"name" : "Freebet",
"calculator" : {"type":"fixed","value":"100"}
}
]
}
]
}
]
and have written the following query to extract properties from conditionDefinitions :
select conditionDefinitions->'properties' as properties from tcampaign cmp
LEFT JOIN LATERAL json_array_elements(steps) singleStep ON true
LEFT JOIN LATERAL json_array_elements(singleStep->'rewardConditions') rewardConditions on TRUE
LEFT JOIN LATERAL json_array_elements(rewardConditions->'conditionDefinitions') conditionDefinitions on TRUE
where properties is not null ;
but I get the following error :
ERROR: column "properties" does not exist
LINE 5: where properties is null ;
If I remove the where clause the query runs fine. Why do I not have access to properties in the where clause? Because I can see results coming back if I remove the WHERE clause, so the query does have results

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

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;

azure search exact match of file name not returning exact results

I am indexing all the file names into the index. But when I search with exact file name in the search query it is returning all other file names also. below is my index definition.
{
"fields": [
{
"name": "id",
"type": "Edm.String",
"facetable": true,
"filterable": true,
"key": true,
"retrievable": true,
"searchable": false,
"sortable": false,
"analyzer": null,
"indexAnalyzer": null,
"searchAnalyzer": null,
"synonymMaps": [],
"fields": []
},
{
"name": "FileName",
"type": "Edm.String",
"facetable": false,
"filterable": false,
"key": false,
"retrievable": true,
"searchable": true,
"sortable": false,
"analyzer": "keyword-analyzer",
"indexAnalyzer": null,
"searchAnalyzer": null,
"synonymMaps": [],
"fields": []
}
],
"scoringProfiles": [],
"defaultScoringProfile": null,
"corsOptions": null,
"analyzers": [
{
"name": "keyword-analyzer",
"#odata.type": "#Microsoft.Azure.Search.CustomAnalyzer",
"charFilters": [],
"tokenizer": "keyword_v2",
"tokenFilters": ["lowercase", "my_asciifolding", "my_word_delimiter"]
}
],
"tokenFilters": [
{
"#odata.type": "#Microsoft.Azure.Search.AsciiFoldingTokenFilter",
"name": "my_asciifolding",
"preserveOriginal": true
},
{
"#odata.type": "#Microsoft.Azure.Search.WordDelimiterTokenFilter",
"name": "my_word_delimiter",
"generateWordParts": true,
"generateNumberParts": false,
"catenateWords": false,
"catenateNumbers": false,
"catenateAll": false,
"splitOnCaseChange": true,
"preserveOriginal": true,
"splitOnNumerics": true,
"stemEnglishPossessive": false,
"protectedWords": []
}
],
"#odata.etag": "\"0x8D6FB2F498F9AD2\""
}
Below is my sample data
{
"value": [
{
"id": "1",
"FileName": "SamplePSDFile_1psd2680.psd"
},
{
"id": "2",
"FileName": "SamplePSDFile-1psd260.psd"
},
{
"id": "3",
"FileName": "SamplePSDFile_1psd2689.psd"
},
{
"id": "4",
"FileName": "SamplePSDFile-1psdxx2680.psd"
}
]
}
Below is the Analyze API results
{
"tokens": [
{
"token": "samplepsdfile_1psd2689.psd",
"startOffset": 0,
"endOffset": 26,
"position": 0
},
{
"token": "samplepsdfile",
"startOffset": 0,
"endOffset": 13,
"position": 0
},
{
"token": "psd",
"startOffset": 15,
"endOffset": 18,
"position": 1
},
{
"token": "psd",
"startOffset": 23,
"endOffset": 26,
"position": 2
}
]
}
When I search with the keyword "SamplePSDFile_1psd2689.psd", Azure search returning three records in the results instead of only document 3. Below is my search query and the results.
?search="SamplePSDFile_1psd2689.psd"&api-version=2019-05-06&$count=true&queryType=full&searchMode=All
{
"#odata.count": 3,
"value": [
{
"#search.score": 2.3387241,
"id": "2",
"FileName": "SamplePSDFile-1psd260.psd"
},
{
"#search.score": 2.2493405,
"id": "3",
"FileName": "SamplePSDFile_1psd2689.psd"
},
{
"#search.score": 2.2493405,
"id": "1",
"FileName": "SamplePSDFile_1psd2680.psd"
}
]
}
How I can achieve my expected results. I tried with and without double quotes around the keyword all other options, but no luck. What I am doing wrong here in this case?
Some body suggested to use $filter, but that field wasn't filterable in our case.
Please help me on this.
If you are looking for exact match then you probably don't want any analyzer involved. Give it a try with this line
"analyzer": "keyword-analyzer"
changed to
"analyzer": null
If you need to be able to do exact match on the field and also support partial keyword searches then you need to index the field twice with different names. Maybe append “Exact” to the exact match field name and don’t use an analyzer for that one. The name without exact can have an analyzer. Then search on the field using the right field name index depending on the type of search.

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>