Update the value of an attribute in a postgresql jsonb array of objects across muliple records

故事扮演 提交于 2020-08-10 20:32:28

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!