问题
I am trying to update a value tit in three database records that is part of a jsonb array object to change the title of gid 1 to 'newTitle Group 1' from just 'group 1' using postgresql and python.
create table groups (name varchar, grp jsonb)
insert into groups (name, grp) values
('joe', [{"gid": "1", "ona": "joe", "tit": "group 1 "}, {"gid": "2", "ona": "harry", "tit": "tester1 group 2"}, {"gid": "3", "ona": "moe", "tit": "group 3"}]),
('harry', [{"gid": "1", "ona": "joe", "tit": "group 1 "}, {"gid": "2", "ona": "harry", "tit": "tester1 group 2"}, {"gid": "3", "ona": "moe", "tit": "group 3"}])
('moe' , [{"gid": "1", "ona": "joe", "tit": "group 1 "}, {"gid": "2", "ona": "harry", "tit": "tester1 group 2"}, {"gid": "3", "ona": "moe", "tit": "group 3"}])
I want to get the result:
('joe', [{"gid": "1", "ona": "joe", "tit": "newTitle Group 1'"}, {"gid": "2", "ona": "harry", "tit": "tester1 group 2"}, {"gid": "3", "ona": "moe", "tit": "group 3"}]),
('harry', [{"gid": "1", "ona": "joe", "tit": "newTitle Group 1'"}, {"gid": "2", "ona": "harry", "tit": "tester1 group 2"}, {"gid": "3", "ona": "moe", "tit": "group 3"}])
('moe' , [{"gid": "1", "ona": "joe", "tit": "newTitle Group 1'"}, {"gid": "2", "ona": "harry", "tit": "tester1 group 2"}, {"gid": "3", "ona": "moe", "tit": "group 3"}])
I have not found a way to do it, please help. Seems like most of the postgresql 9.5 capabilities are for jsonb objects but not arrays of objects.
I tried to use many examples on the web but all seemed to fail. I also would consider using a where clause statement on the actual query to limit the jsonb records being searched by for example including WHERE name IN ('harry', 'moe')
but for now just need to see how this basic update issue is solved.
回答1:
Just need to use REPLACE()
function including ::text and ::jsonb conversions within the DB, without need of any extra operation in the python code :
UPDATE groups
SET grp = REPLACE(grp::text, '"tit": "group 1 "','"tit": "newTitle Group 1 "')::jsonb
Demo
Of course, it's possibile to add a where condition such as WHERE name IN ('harry', 'moe')
to restrict the update.
UPDATE 1:
If you need to perform the update for a spesific record within the jsonb object such as
WHERE j->>'ona' = 'joe'
, then use jsonb_array_elements()
function within your statement as :
UPDATE groups AS g
SET grp = REPLACE(grp::text, '"tit": "group 1 "','"tit": "newTitle Group 1 "')::json
WHERE g.name IN ( SELECT g.name
FROM groups AS g
CROSS JOIN jsonb_array_elements(grp) AS j
WHERE j.value->>'ona' = 'joe' )
Demo
UPDATE 2:
If you want to find the desired value(gid=1
in this case) within the jsonb column dynamically in order to derive the path, then it's possible to use jsonb_set()
function as :
WITH T AS
(
SELECT ('{'||index-1||',tit}')::text[] AS path
FROM groups AS g2
CROSS JOIN jsonb_array_elements(grp)
WITH ORDINALITY arr(j,index)
WHERE j->>'gid'='1'
)
UPDATE groups AS g
SET grp = jsonb_set(grp,t.path,'"newTitle Group 1 "',false)
FROM t
Demo
来源:https://stackoverflow.com/questions/62844583/update-the-value-of-an-attribute-in-a-postgresql-jsonb-array-of-objects-across-m