sqljsondatabasepostgresqljsonb

Update a JSON property in a text column that contains a JSON object


I have a table that contains two columns. The primary key and a column called comments that is a text column but contains a json object. Now, I want to update all properties in all columns where the property has a value, by diving that value by 100. However, this doesn't work, since it just sets these properties to null instead:

do $$
declare
  commentKey text;
  commentKeys text[] := array['test1','test2'];
begin
   FOREACH commentKey IN ARRAY commentKeys
  loop
     UPDATE a
     SET comments = jsonb_set(to_jsonb(comments), ('{'||commentKey||'}')::text[], to_jsonb(round(((to_json(comments) ->> commentKey)::numeric) / 100, 6)))
     WHERE comments::jsonb ->> commentKey is not null;
  end loop;
end;
$$ language plpgsql;

Here's a DB fiddle: https://dbfiddle.uk/uhEChx-S

What am I doing wrong?


Solution

  • You can use jsonb_object_agg to build new JSON objects, where keys that match the contents of commentKeys have their values divided by 100, if the value is not null:

    do $$
    declare
      commentKey text;
      commentKeys text[] := array['test1','test2'];
    begin
       update a set comments = (select jsonb_object_agg(k.key, 
           case when k.value#>>'{}' is not null and k.key::text = any(commentKeys) 
                  then (k.value::text::float / 100)::text::jsonb 
                else k.value end) 
           from jsonb_each(comments::jsonb) k);
    end;
    $$ language plpgsql;
    

    See fiddle