Accessing an Array Inside JSON with a Postgres Query - json

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"

Related

Return a MySQL result, with results formated as JSON, with row id as the JSON key for each row result

A query like this:
SELECT JSON_ARRAYAGG(JSON_OBJECT('id', id, 'tag', tag)) from all_tags;
produces a result like this:
[
{
"id": 979,
"tag": "alternative"
},
{
"id": 947,
"tag": "ambient"
}
]
The above is ok, but what I really want is to get a result like this:
[
979:{
"tag": "alternative"
},
947: {
"tag": "ambient"
}
]
Is this possible to do only using mysql?
I've tried SELECT JSON_ARRAYAGG(JSON_OBJECT(id, JSON_OBJECT( 'tag', tag))) from all_tags;
This does allow me to nest columns as a value for a row id. But it doesn't really help as the key is still nested in an object.
Ultimately I'm hoping to use the result as a map in Javacript to look up properties by key. I could shape the data in JS, I'm just curious if it can be done with MySQL
What you show is not valid JSON. If you use the square brackets [ ] then it's just an array, not an object. But if you use the key: value format, that's an object, not an array.
I think the following comes closer to what you want:
SELECT JSON_OBJECTAGG(id, JSON_OBJECT( 'tag', tag)) from all_tags;

Use JSON file in postgresql database

I have a table in a postgresql database with one field with json format.
It's look like this :
[
{
"transition": "transition1",
"from": "step1",
"to": "step2",
"date": {
"date": "2021-01-30 15:34:06.840859"
}
},
{
"transition": "transition2",
"from": "step2",
"to": "step3",
"date": {
"date": "2021-01-30 16:52:00.412208"
}
}
]
I want to have a new column with the date of transition1.
I tried a lot of things but I can't figure out how to extract this date, I can't use the index because the number of transition is not fixed, some user could have 3 and other more than 10.
You need to iterate over all array elements to find the correct one:
select (select (item -> 'date' ->> 'date')::timestamp
from jsonb_array_elements(jsonb_column) as x(item)
where item ->> 'transition' = 'transition1') as transition_date
from the_table
;
If you column is defined as json rather than jsonb (which it should be) you need to use json_array_elements() instead.

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'

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.

Json output format from SQL Server 2017

I have a stored procedure in SQL Server 2017 that outputs a result set as JSON. It works to output the set just fine, but I want it in a different format.
According to the MS documentation, the format it's sending out is as expected, but it seems counter-intuitive to me. I'm not JSON expert by any means but I've always assumed it to be a single object representation of a structure.
The query is:
SELECT
e.EventID AS 'Event.ID',
EventDate AS 'Event.Date',
ea.ActivityID AS 'Event.Activity.ID',
ea.CreateDate AS 'Event.Activity.Date',
ea.Notes AS 'Event.Activity.Notes'
FROM
Events e
JOIN
dbo.EventActivities ea ON e.EventID = ea.EventID
FOR JSON PATH
This returns an output of:
[
{"Event": {
"ID":"236",
"Date":"2019-03-01",
"Activity": {"ID": 10,
"Date":"2019-01-02T11:47:33.2800000",
"Notes":"Event created"}
}
},
{"Event": {
"ID":"236",
"Date":"2019-03-01",
"Activity": {"ID":20,
"Date":"2019-01-02T11:47:34.3933333",
"Notes":"Staff selected"}
}
},
{"Event": {
"ID":"236",
"Date":"2019-03-01",
"Activity": {"ID":20,
"Date":"2019-01-02T11:47:34.3933333",
"Notes":"Staff selected"}
}
}
]
When I format this manually (to visualise it better, it's giving me an array of 3 identical events, for each activity. This is consistent with what MS say in Format Nested JSON
I was expecting (or rather hoping) to see something like:
[
{
"Event": {
"ID": "236",
"Date": "2019-03-01",
"Activity": [
{
"ID": 10,
"Date": "2019-01-02T11:47:33.2800000",
"Notes": "Event created"
},
{
"ID": 20,
"Date": "2019-01-02T11:47:34.3933333",
"Notes": "Staff selected"
},
{
"ID": 20,
"Date": "2019-01-02T11:47:34.3933333",
"Notes": "Staff selected"
}
]
}
}
]
Is it possible to get an output formulated like this? or would this be invalid?
To start, you can test if a JSON String is valid with ISJSON. The expected output you indicated does not pass validation, but is close. It is missing a "[]" for the inner array.
However, I see where you were going with this. To better explain what I think the issue you are running into is, I am going to beautify the format of the output JSON from your query to match your expected JSON.
Original output as follows:
[
{"Event":
{"ID":"236","Date":"2019-03-01",
"Activity":{
"ID":10,"Date":"2019-01-02T11:47:33.2800000","Notes":"Event created"
}
}
},
{"Event":
{"ID":"236","Date":"2019-03-01",
"Activity":{
"ID":20,"Date":"2019-01-02T11:47:34.3933333","Notes":"Staff selected"}
}
},
{"Event":
{"ID":"236","Date":"2019-03-01",
"Activity":{
"ID":20,"Date":"2019-01-02T11:47:34.3933333","Notes":"Staff selected"
}
}
}
]
Based on your ideal format, a possible valid JSON string would be as follows:
{"Event":
[
{"ID":236,"Date":"2019-03-01",
"Activity":
[
{"ID":10,"Date":"2019-01-02T11:47:33.2800000","Notes":"Event created"},
{"ID":20,"Date":"2019-01-02T11:47:34.3933333","Notes":"Staff selected"},
{"ID":20,"Date":"2019-01-02T11:47:34.3933333","Notes":"Staff selected"}
]
}
]
}
You can achieve this by adjusting your table alias for the second table and using FOR JSON AUTO and ROOT. It will return an output with the "Event" attributes not repeated for each of its "EventActivities". For each "Event" it will put its related "EventActivities" into an array instead.
The following SQL will return the desired output:
SELECT [Event].EventID AS 'ID',
[Event].EventDate AS 'Date',
Activity.ActivityID AS 'ID',
Activity.CreateDate AS 'Date',
Activity.Notes AS 'Notes'
FROM #Events [Event]
JOIN #EventActivities Activity
ON [Event].EventID = Activity.EventID
FOR JSON AUTO, ROOT('Event')
The exact output for this will be as follows:
{"Event":[{"ID":236,"Date":"2019-03-01","Activity":[{"ID":10,"Date":"2019-01-02T11:47:33.2800000Z","Notes":"Event created"},{"ID":20,"Date":"2019-01-02T11:47:33.2800000Z","Notes":"Staff selected"},{"ID":20,"Date":"2019-01-02T11:47:33.2800000Z","Notes":"Staff selected"}]}]}
It will not return in a beautified format, but spaces and indentation can be added without compromising the fact that it is valid JSON, while also achieving the intended array requirements.
Your expected output is not a valid JSON. But, assuming you are referring Activity field as an array of activities, you can use nested queries.
SELECT
E.EventID AS 'Event.ID',
E.EventDate AS 'Event.Date',
(
SELECT
A.ActivityID AS 'ID',
A.CreateDate AS 'Date',
A.Notes AS 'Notes'
FROM dbo.EventActivities AS A
WHERE A.EventID = E.EventID
FOR JSON PATH
) AS 'Event.Activities'
FROM dbo.Events AS E
FOR JSON PATH