Concatenate list from JSON array - postgresql

Let's say I have json in the database of items:
Row1:
{"Id": "1", "Items": [{"Item": "Test Item", "Price": "$5.00"}, {"Item": "Test Item #2", "Price": "$15.00"}]}
Row2:
{"Id": "2", "Items": [{"Item": "Test Item #3", "Price": "$1.00"}, {"Item": "Test Item #1", "Price": "$4.00"}]}
How do I get rows formatted like this (| is column seperator):
1 | Test Item, Test Item #2
2 | Test Item #3, Test Item #1

SELECT ID || '|' || ARRAY_TO_STRING( ARRAY_AGG( ITEMS ), ', ')
FROM
(
SELECT T.J->>'Id' AS ID, json_array_elements((T.J->'Items')::json)->>'Item' AS ITEMS
FROM
(
SELECT ('{"Id": "1", "Items": [{"Item": "Test Item", "Price": "$5.00"}, {"Item": "Test Item #2", "Price": "$15.00"}]}')::json AS J
UNION all
SELECT ('{"Id": "2", "Items": [{"Item": "Test Item #3", "Price": "$1.00"}, {"Item": "Test Item #1", "Price": "$4.00"}]}')::json AS J
) T
) T
GROUP BY ID

Related

Jsonb array of objects update

So this is my jsonb array of objects. Column is called bids in my db.
bids column
[
{
"id": "1",
"size": "5.5Y",
"price": 180
},
{
"id": "f0d1d36a-f6af-409e-968e-54c1dc104566",
"size": "6.5Y",
"price": 22
}
]
I want to update price property by the ID of an element for ex. "f0d1d36a-f6af-409e-968e-54c1dc104566", so the price would change from 22 to 150 IN ROW WHICH CONTAINS ELEMENT WITH DESIRED ID IN THE COLUMN.
How can I do that?
create table json_update (id integer, json_fld jsonb);
insert into json_update values (1, '[
{
"id": "1",
"size": "5.5Y",
"price": 180
},
{
"id": "f0d1d36a-f6af-409e-968e-54c1dc104566",
"size": "6.5Y",
"price": 22
}
]'
)
;
UPDATE
json_update
SET
json_fld = jsonb_set(json_fld, ARRAY[(idx)::text, 'price'::text], '150'::jsonb)
FROM (
SELECT
(row_number() OVER (ORDER BY t.a ->> 'id') - 1) AS idx,
t.a
FROM (
SELECT
jsonb_array_elements(json_fld)
FROM
json_update) AS t (a)) AS i
WHERE
i.a ->> 'id' = 'f0d1d36a-f6af-409e-968e-54c1dc104566';
select * from json_update ;
id | json_fld
----+---------------------------------------------------------------------------------------------------------------------------
1 | [{"id": "1", "size": "5.5Y", "price": 180}, {"id": "f0d1d36a-f6af-409e-968e-54c1dc104566", "size": "6.5Y", "price": 150}]

Redshift: can't parse multiple items from list in JSON to each row

I have a JSON in the RedShift.
"value" is stored in the inputs column as JSON text. Create a unique record for each "value". Look at the example below this table:
{"inputs": [{"name": "ambient", "desc": "Select from below the ambient setting that best decribe your environment right now", "values": ["Indoor - Loud", "Indoor - Normal", "Indoor - Whisper", "Outdoor - Loud", "Outdoor - Normal", "Outdoor - Whisper", "Semi-Outdoor - Loud", "Semi-Outdoor - Normal", "Semi-Outdoor - Whisper"]}
As a result it must be like this:
ProjectId : 10. Input value = Indoor – Loud
ProjectId : 10. Input value = Indoor – Normal
ProjectId : 10. Input value Indoor – Whisper
Each value need to be stored as one row in the dim_collect_user_inp_configs table. Example, Indoor-Loud as one row and it will have it’s own unique identifier as prompt_input_value_id, Indoor-Normal as one row and it will have it’s own unique identifier as prompt_input_value_id till the Semi-Outdoor-Whisper.
There could be multiple input “name” in one inputs column. Each name and its value need to be stored separately. Example :
[{"desc": "How many people does the video contain?", "name": "Number of People", "type": "dropdown", "values": ["", "Only 1", "2-3", "3+"]}, {"desc": "What is the camera position?", "name": "Movement", "type": "dropdown", "values": ["", "Fixed position", "Moving"]}, {"desc": "From which angle did you shoot the video?", "name": "Shoot Angle", "type": "dropdown", "values": ["", "Frontal recording", "Tight angle: 10-40 degree", "Wide angle: 40-70 degree"]}, {"desc": "From which distance did you shoot the video?", "name": "Distance", "type": "dropdown", "values": ["", "Near/Selfie", "Mid (3-6 ft)", "Far (>6 ft)"]}, {"desc": "What is the video lighting direction?", "name": "Lighting Direction", "type": "dropdown", "values": ["", "Front lit", "Side lit", "Back lit"]}, {"desc": "What is the video background?", "name": "Background", "type": "dropdown", "values": ["", "Outdoors", "In office", "At home", "Plain background"]}, {"desc": "What is the topic in your speech?", "name": "Topic", "type": "dropdown", "values": ["", "Arts and Media", "Business", "Education", "Entertainment", "Food/Eating", "Nutrition", "Healthcare ", "High School Life", "Mental Health", "News", "Technology", "Morals and Ethics", "Phones and Apps", "Sports", "Science"]}]
I try to do it with this query:
WITH all_values AS (
SELECT projectid AS projectid,
prompttype AS prompttype,
json_extract_path_text(json_extract_array_element_text(inputs, 0, True), 'name') AS name,
json_extract_path_text(json_extract_array_element_text(inputs, 0, True), 'desc') AS description,
json_extract_path_text(json_extract_array_element_text(inputs, 0, True), 'values') AS value,
scriptid AS scriptid,
corpuscode AS corpuscode
FROM source.table
WHERE
prompttype = 'input'
GROUP BY projectid, prompttype, name, description, scriptid, corpuscode, value
LIMIT 10
)
SELECT * FROM all_values;
But now I haven't each row for "value" as I need. :(
Can you help me?
Thnx.

Create multiple UUIDs for postgres jsonb

I have a database of a couple million records that look like this:
{
"id": "aa1e24cd-2825-490f-8ccb-60bd4914dc20",
"circulationNotes": [
{
"note": "REFERENCE BOOK",
"noteType": "Check in"
},
{
"note": "REFERENCE BOOK",
"noteType": "Check out"
}
],
"holdingsRecordId": "fd79910f-4d11-41b4-9e53-198fff089917",
"permanentLocationId": "cee4d952-da5a-4d34-bb0a-a5d4d4581f39"
}
I need to generate and add a uuid to each of the circulationNotes lacking them (~ 10K records) so the desired output is
{
"id": "aa1e24cd-2825-490f-8ccb-60bd4914dc20",
"circulationNotes": [
{
"id": "3794824a-b814-4b94-b7c4-d8be53088a51",
"note": "REFERENCE BOOK",
"noteType": "Check in"
},
{
"id": "175989f9-16f4-4cfe-a1aa-d665ec1263e7",
"note": "REFERENCE BOOK",
"noteType": "Check out"
}
],
"holdingsRecordId": "fd79910f-4d11-41b4-9e53-198fff089917",
"permanentLocationId": "cee4d952-da5a-4d34-bb0a-a5d4d4581f39"
}
I can select the records I want to update with the query:
SELECT id
FROM mod_inventory_storage.item
WHERE EXISTS
( SELECT *
FROM jsonb_array_elements(jsonb->'circulationNotes')
WHERE value->'note' IS NOT NULL
AND value->'id' IS NULL )
(data is such that if one note has the problem, both do)
but how do I update the jsonb object with uuids in each entry within circulationNotes?
I replicated your case with the following
create table test (id serial, text jsonb);
insert into test (text) values ('{
"id": "aa1e24cd-2825-490f-8ccb-60bd4914dc20",
"circulationNotes": [
{
"note": "REFERENCE BOOK",
"noteType": "Check in"
},
{
"note": "REFERENCE BOOK",
"noteType": "Check out"
}
],
"holdingsRecordId": "fd79910f-4d11-41b4-9e53-198fff089917",
"permanentLocationId": "cee4d952-da5a-4d34-bb0a-a5d4d4581f39"
}');
insert into test (text) values ('{
"id": "aa1e24cd-2825-490f-8ccb-60bd4914dc20",
"circulationNotes": [
{
"note": "REFERENCE BOOK",
"noteType": "Check in"
},
{
"note": "REFERENCE BOOK",
"noteType": "Check out"
}
],
"holdingsRecordId": "fd79910f-4d11-41b4-9e53-198fff089917",
"permanentLocationId": "cee4d952-da5a-4d34-bb0a-a5d4d4581f39"
}');
insert into test (text) values ('{
"id": "aa1e24cd-2825-490f-8ccb-60bd4914dc20",
"circulationNotes": [
{
"note": "REFERENCE BOOK",
"noteType": "Check in"
},
{
"note": "REFERENCE BOOK",
"noteType": "Check out"
}
],
"holdingsRecordId": "fd79910f-4d11-41b4-9e53-198fff089917",
"permanentLocationId": "cee4d952-da5a-4d34-bb0a-a5d4d4581f39"
}');
insert into test (text) values ('{
"id": "aa1e24cd-2825-490f-8ccb-60bd4914dc20",
"circulationNotes": [
{
"id": "3794824a-b814-4b94-b7c4-d8be53088a51",
"note": "REFERENCE BOOK",
"noteType": "Check in"
},
{
"id": "175989f9-16f4-4cfe-a1aa-d665ec1263e7",
"note": "REFERENCE BOOK",
"noteType": "Check out"
}
],
"holdingsRecordId": "fd79910f-4d11-41b4-9e53-198fff089917",
"permanentLocationId": "cee4d952-da5a-4d34-bb0a-a5d4d4581f39"
}');
Then, to solve the issue I split the problem in 2 steps: decomposing and recomposing.
Step 1: create a table at circulationNotes and place the new id column with the following
with fixing_id as (
select id,
text->'id' json_id,
text->'holdingsRecordId' holdingsRecordId,
text->'permanentLocationId' as permanentLocationId,
('{"id":"'||uuid_generate_v1()||'"}')::jsonb || jsonb_array_elements((text->'circulationNotes')::jsonb) as circulationNotes
from test
where exists
(select *
FROM jsonb_array_elements(text->'circulationNotes')
where value->'note' is not null
and value->'id' is null))
select * from fixing_id
The result is the following
id | json_id | holdingsrecordid | permanentlocationid | circulationnotes
----+----------------------------------------+----------------------------------------+----------------------------------------+---------------------------------------------------------------------------------------------------
1 | "aa1e24cd-2825-490f-8ccb-60bd4914dc20" | "fd79910f-4d11-41b4-9e53-198fff089917" | "cee4d952-da5a-4d34-bb0a-a5d4d4581f39" | {"id": "4ad151ea-f5c9-11eb-a458-42010af00961", "note": "REFERENCE BOOK", "noteType": "Check in"}
1 | "aa1e24cd-2825-490f-8ccb-60bd4914dc20" | "fd79910f-4d11-41b4-9e53-198fff089917" | "cee4d952-da5a-4d34-bb0a-a5d4d4581f39" | {"id": "4ad155fa-f5c9-11eb-a458-42010af00961", "note": "REFERENCE BOOK", "noteType": "Check out"}
2 | "aa1e24cd-2825-490f-8ccb-60bd4914dc20" | "fd79910f-4d11-41b4-9e53-198fff089917" | "cee4d952-da5a-4d34-bb0a-a5d4d4581f39" | {"id": "4ad15708-f5c9-11eb-a458-42010af00961", "note": "REFERENCE BOOK", "noteType": "Check in"}
2 | "aa1e24cd-2825-490f-8ccb-60bd4914dc20" | "fd79910f-4d11-41b4-9e53-198fff089917" | "cee4d952-da5a-4d34-bb0a-a5d4d4581f39" | {"id": "4ad157a8-f5c9-11eb-a458-42010af00961", "note": "REFERENCE BOOK", "noteType": "Check out"}
3 | "aa1e24cd-2825-490f-8ccb-60bd4914dc20" | "fd79910f-4d11-41b4-9e53-198fff089917" | "cee4d952-da5a-4d34-bb0a-a5d4d4581f39" | {"id": "4ad15870-f5c9-11eb-a458-42010af00961", "note": "REFERENCE BOOK", "noteType": "Check in"}
3 | "aa1e24cd-2825-490f-8ccb-60bd4914dc20" | "fd79910f-4d11-41b4-9e53-198fff089917" | "cee4d952-da5a-4d34-bb0a-a5d4d4581f39" | {"id": "4ad15906-f5c9-11eb-a458-42010af00961", "note": "REFERENCE BOOK", "noteType": "Check out"}
(6 rows)
Check that I'm using the uuid_generate_v1() function to generate the uuid (you'll need the uuid-ossp extension). And that the jsonb_array_elementscreates a row for eachtext->'circulationNotes'` item.
Step 2: Aggregate from the fixing_id with jsonb_agg and rebuild the json object with jsonb_build_object
select id,
jsonb_build_object('id',json_id,'circulationNotes',jsonb_agg(circulationNotes) ,'holdingsRecordId',holdingsRecordId,'permanentLocationId',permanentLocationId)
from fixing_id
group by id,
json_id,
holdingsRecordId,
permanentLocationId
result
id | jsonb_build_object
----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1 | {"id": "aa1e24cd-2825-490f-8ccb-60bd4914dc20", "circulationNotes": [{"id": "b71fc232-f5c9-11eb-a458-42010af00961", "note": "REFERENCE BOOK", "noteType": "Check in"}, {"id": "b71fc39a-f5c9-11eb-a458-42010af00961", "note": "REFERENCE BOOK", "noteType": "Check out"}], "holdingsRecordId": "fd79910f-4d11-41b4-9e53-198fff089917", "permanentLocationId": "cee4d952-da5a-4d34-bb0a-a5d4d4581f39"}
3 | {"id": "aa1e24cd-2825-490f-8ccb-60bd4914dc20", "circulationNotes": [{"id": "b71fc624-f5c9-11eb-a458-42010af00961", "note": "REFERENCE BOOK", "noteType": "Check in"}, {"id": "b71fc6c4-f5c9-11eb-a458-42010af00961", "note": "REFERENCE BOOK", "noteType": "Check out"}], "holdingsRecordId": "fd79910f-4d11-41b4-9e53-198fff089917", "permanentLocationId": "cee4d952-da5a-4d34-bb0a-a5d4d4581f39"}
2 | {"id": "aa1e24cd-2825-490f-8ccb-60bd4914dc20", "circulationNotes": [{"id": "b71fc4b2-f5c9-11eb-a458-42010af00961", "note": "REFERENCE BOOK", "noteType": "Check in"}, {"id": "b71fc55c-f5c9-11eb-a458-42010af00961", "note": "REFERENCE BOOK", "noteType": "Check out"}], "holdingsRecordId": "fd79910f-4d11-41b4-9e53-198fff089917", "permanentLocationId": "cee4d952-da5a-4d34-bb0a-a5d4d4581f39"}
(3 rows)
The whole query is
with fixing_id as (
select id,
text->'id' json_id,
text->'holdingsRecordId' holdingsRecordId,
text->'permanentLocationId' as permanentLocationId,
('{"id":"'||uuid_generate_v1()||'"}')::jsonb || jsonb_array_elements((text->'circulationNotes')::jsonb) as circulationNotes
from test
where exists
(select *
FROM jsonb_array_elements(text->'circulationNotes')
where value->'note' is not null
and value->'id' is null))
select id,
jsonb_build_object('id',json_id,'circulationNotes',jsonb_agg(circulationNotes) ,'holdingsRecordId',holdingsRecordId,'permanentLocationId',permanentLocationId)
from fixing_id
group by id,
json_id,
holdingsRecordId,
permanentLocationId

Can't sort by all array's items?

Postgresq 9.6
json
"availability": [
{
"qty": 25,
"price": 1599,
"is_available": true
},
{
"qty": 72,
"price": 3599,
},
"is_available": true
]
table with column data. Type is jsonb
If I want to sort first array's(availability) item by field "price" I this:
SELECT *
from product prod
WHERE to_tsvector('english', prod.data) ## to_tsquery('gram')
ORDER BY prod.data #> '{availability,0,price}' desc
OK.
But I need to sort all fields "price" in array availability
Smt like this (pseudo code)
SELECT *
from product prod
WHERE to_tsvector('english', prod.data) ## to_tsquery('gram')
ORDER BY prod.data #> '{availability,*,price}' desc
I need to to order by "price" desc.
The result must be
First record of result is second json
"availability": [
{
"qty": 25,
"price": 11599,
"is_available": true
},
{
"qty": 72,
"price": 13599,
},
"is_available": true
]
...
"availability": [
{
"qty": 25,
"price": 1599,
"is_available": true
},
{
"qty": 72,
"price": 3599,
},
"is_available": true
]
Is it possible?
This could be done like this:
select id,
jsonb_set(data, '{availability}',
(select jsonb_agg(item order by (item ->> 'price')::numeric)
from jsonb_array_elements(data -> 'availability') as x(item))
) as data
from product
where ...

Search and update a JSON array element in Postgres

I have a Jsonb column that store array of elements like the following:
[
{"id": "11", "name": "John", "age":"25", ..........},
{"id": "22", "name": "Mike", "age":"35", ..........},
{"id": "33", "name": "Tom", "age":"45", ..........},
.....
]
I want to replace the 2nd object(id=22) with a totally new object. I don't want to update each property one by one because there are many properties and their values all could have changed. I want to just identify the 2nd element and replace the whole object.
I know there is a jsonb_set(). However, to update the 2nd element, I need to know its array index=1 so I can do the following:
jsonb_set(data, '{1}', '{"id": "22", "name": "Don", "age":"55"}',true)
But I couldn't find any way to search and get that index. Can someone help me out?
One way I can think of is to combine row_number and json_array_elements:
-- test data
create table test (id integer, data jsonb);
insert into test values (1, '[{"id": "22", "name": "Don", "age":"55"}, {"id": "23", "name": "Don2", "age":"55"},{"id": "24", "name": "Don3", "age":"55"}]');
insert into test values (2, '[{"id": "32", "name": "Don", "age":"55"}, {"id": "33", "name": "Don2", "age":"55"},{"id": "34", "name": "Don3", "age":"55"}]');
select subrow, id, row_number() over (partition by id)
from (
select json_array_elements(data) as subrow, id
from test
) as t;
subrow | id | row_number
------------------------------------------+----+------------
{"id": "22", "name": "Don", "age":"55"} | 1 | 1
{"id": "23", "name": "Don2", "age":"55"} | 1 | 2
{"id": "24", "name": "Don3", "age":"55"} | 1 | 3
{"id": "32", "name": "Don", "age":"55"} | 2 | 1
{"id": "33", "name": "Don2", "age":"55"} | 2 | 2
{"id": "34", "name": "Don3", "age":"55"} | 2 | 3
-- apparently you can filter what you want from here
select subrow, id, row_number() over (partition by id)
from (
select json_array_elements(data) as subrow, id
from test
) as t
where subrow->>'id' = '23';
In addition, think about your schema design. It may not be the best idea to store your data this way.