JSON to SQL Table with nested properties - json

I am trying to develop database table structure from following JSON Structure. "requiredfields" are straight forward and I table setup for those. However, I am stuck on how to created schema to store "Configuration" and its nested properties in SQL Database. Any help will be appreciated. Thanks.
{
"requiredFields": [
"hello",
"world"
],
"configuration": {
"hello": {
"fallbacks": [
{
"type": "constant",
"value": "30"
}
]
},
"world": {
"fallbacks": [
{
"type": "fromInputFile",
"value": "patientFirstName"
},
{
"type": "fromInputFile",
"value": "subscriberFirstName"
},
{
"type": "constant",
"value": "alpha"
}
]
}
}
}

It looks like you could store that in a single table
CREATE TABLE ConfigurationFallbacks (
field nvarchar(100),
type nvarchar(100),
value nvarchar(100)
);
You may also want to add another table to store just the field values, and the table above would be foreign-keyed to that.
You can insert like this:
INSERT ConfigurationFallbacks (field, type, value)
SELECT
keys.[key],
j.type,
j.value
FROM OPENJSON(#json, '$.configuration') keys
CROSS APPLY OPENJSON(keys.value, '$.fallbacks')
WITH (
type nvarchar(100),
value nvarchar(100)
) j;
The first OPENJSON call does not have a schema, so it returns a set of key value pairs.

Related

Retrieve specific value from a JSON blob in MS SQL Server, using a property value?

In my DB I have a column storing JSON. The JSON looks like this:
{
"views": [
{
"id": "1",
"sections": [
{
"id": "1",
"isToggleActive": false,
"components": [
{
"id": "1",
"values": [
"02/24/2021"
]
},
{
"id": "2",
"values": []
},
{
"id": "3",
"values": [
"5393",
"02/26/2021 - Weekly"
]
},
{
"id": "5",
"values": [
""
]
}
]
}
]
}
]
}
I want to create a migration script that will extract a value from this JSON and store them in its own column.
In the JSON above, in that components array, I want to extract the second value from the component with an ID of "3" (among other things, but this is a good example). So, I want to extract the value "02/26/2021 - Weekly" to store in its own column.
I was looking at the JSON_VALUE docs, but I only see examples for specifing indexes for the json properties. I can't figure out what kind of json path I'd need. Is this even possible to do with JSON_VALUE?
EDIT: To clarify, the views and sections components can have static array indexes, so I can use views[0].sections[0] for them. Currently, this is all I have with my SQL query:
SELECT
*
FROM OPENJSON(#jsonInfo, '$.views[0].sections[0]')
You need to use OPENJSON to break out the inner array, then filter it with a WHERE and finally select the correct value with JSON_VALUE
SELECT
JSON_VALUE(components.value, '$.values[1]')
FROM OPENJSON (#jsonInfo, '$.views[0].sections[0].components') components
WHERE JSON_VALUE(components.value, '$.id') = '3'

Accessing an Array Inside JSON with a Postgres Query

I have a table with a data_type of json that I need to query one of the properties inside of it.
This is what the data in the column looks like:
{
"id": 7008,
"access_links": [
{
"product_code": "PRODUCT-1",
"link": "https://some.url"
},
{
"product_code": "PRODUCT-2",
"link": "https://someOther.url"
}
],
"library_id": "2d1203db-75b3-43a5-947c-8555b48371db"
}
I need to be able to pull out and filter by the product_code nested inside of the access_links.
I can get one layer deep by using this query:
SELECT
courses.course_metadata -> 'access_links' as access_links
FROM
courses
This seems to get me into the column, but I can't query any further.
The output I receive from the query looks like:
[{"product_code":"PRODUCT-1","link":"https://some.url"},{"product_code":"PRODUCT-2","link":"https://someOther.url"}]
I've tried using the ->> and #>> operators, but they both complain about the array not starting with a {. Also worth noting that the column is a data type of JSON not JSONB, so the #> operator doesn't work.
What am I missing here?
Does this help?
select
json_array_elements (x->'access_links')->'product_code' as product_code
from
(select '{
"id": 7008,
"access_links": [
{
"product_code": "PRODUCT-1",
"link": "https://some.url"
},
{
"product_code": "PRODUCT-2",
"link": "https://someOther.url"
}
],
"library_id": "2d1203db-75b3-43a5-947c-8555b48371db"
}'::json x
) as v
;
product_code
"PRODUCT-1"
"PRODUCT-2"

Postgres - updating an array element in a json column

I have a json column in a postgres table.
The column contains the following json data:
{
"data": {
"id": "1234",
"sites": [
{
"site": {
"code": "1",
"display": "Site1"
}
},
{
"site": {
"code": "2",
"display": "Site2"
},
"externalSite": true
},
{
"site": {
"code": "3",
"display": "Site3"
}
}
]
}
}
I need to create an update query that adds another attribute ('newAttribute' in the sample below) to all array items that have '"externalSite": true', so, after running the update query the second array element will be:
{
"site": {
"code": "2",
"display": "Site2"
},
"externalSite": true,
"newAttribute": true
}
The following query returns the array elements that need to be updated:
select * from myTable, jsonb_array_elements(data -> 'sites') sites
where sites ->'externalSite' = 'true'
What is the syntax of the update query?
Thanks
Kobi
Assuming your table is called test and your column is called data, you can update it like so:
UPDATE test SET data =
(select jsonb_set(data::jsonb, '{"data","sites"}', sites)
FROM test
CROSS JOIN LATERAL (
SELECT jsonb_agg(CASE WHEN site ? 'externalSite' THEN site || '{"newAttribute":"true"}'::jsonb
ELSE site
END) AS sites
FROM jsonb_array_elements( (data#>'{"data","sites"}')::jsonb ) as ja(site)
) as sub
);
Note that I cast the data to jsonb data as there are more functions and operators available for manipulating jsonb than plain json.
You can run the SELECT statement alone to see what it is doing, but the basic idea is to re-create the sites object by expanding it with jsonb_array_elements and adding the newAttribute attribute if externalSite exists.
This array is then aggregated with jsonb_agg and, finally, in the outer select, the sites object is replaced entirely with this newly computed version.

Globally replace in Postgres JSONB field

I need to globally replace a particular string that occurs multiple places in a nested JSON structure, thats stored as jsonb in a postgres table. For example:
{
"location": "tmp/config",
"alternate_location": {
"name": "config",
"location": "tmp/config"
}
}
...should become:
{
"location": "tmp/new_config",
"alternate_location": {
"name": "config",
"location": "tmp/new_config"
}
}
I've tried:
UPDATE files SET meta_data = to_json(replace(data::TEXT, 'tmp/config', 'tmp/new_config'));
Unfortunately this results in malformed JSON, with triple escaped quotes.
Any ideas how to do this?
Use a simple cast to jsonb instead of to_json(), e.g.:
with files(meta_data) as (
values(
'{
"location": "tmp/config",
"alternate_location": {
"name": "config",
"location": "tmp/config"
}
}'::jsonb)
)
select replace(meta_data::text, 'tmp/config', 'tmp/new_config')::jsonb
from files;
replace
--------------------------------------------------------------------------------------------------------
{"location": "tmp/new_config", "alternate_location": {"name": "config", "location": "tmp/new_config"}}
(1 row)
Use update:
UPDATE files
SET meta_data = replace(data::TEXT, 'tmp/config', 'tmp/new_config')::jsonb;

Convert nested json to Cassandra

I run into a problem when trying to convert json data to Cassandra.
The json data is like:
{
"A": {
"A_ID" : "1111"
"field1": "value1",
"field2": "value2",
"field3": [
{
"id": "id1",
"name": "name1",
"segment": [
{
"segment_id": "segment_id_1",
"segment_name": "segment_name_1",
"segment_value": "segment_value_1"
},
{
"segment_id": "segment_id_2",
"segment_name": "segment_name_2",
"segment_value": "segment_value_2"
},
...
]
},
{
"id": "id2",
"name": "name2",
"segment": [
{
"segment_id": "segment_id_3",
"segment_name": "segment_name_3",
"segment_value": "segment_value_3"
},
{
"segment_id": "segment_id_4",
"segment_name": "segment_name_4",
"segment_value": "segment_value_4"
},
...
]
},
...
]
}
}
Thank you very much!
I see a post about composite keys here:
https://pkghosh.wordpress.com/2013/07/14/storing-nested-objects-in-cassandra-composite_columns/
But I do not know what does this post mean because the author did not give a complete solution.
In such cases, you should keep entire json string in database.
For example – You can create a table for "segement" part of the json.
Create table segment_by_id{
Id text,
Name text,
Json text,
PRIMARY KEY (id, name)
WITH CLUSTERING ORDER BY (name DESC);
This way you can divide the json part by part. You can also save the entire json in one table with primary and clustering keys suitable to your needs.
Cassandra uses LZ4 compression so large data can be saved efficiently. Go through Compression documentation to use a compression algoritham for table.