Pgsql Json/Jsonb格式数据更新key值覆盖问题
先贴出问题,pgsql中某jsonb 字段,原始值为{"a":{"a":"b","c":"d"}},来了一个新值{"a":{"a":"e","f":"g"}},我想要的最终值为{"a":{"a":"e","c":"d","f":"g"}},可是使用||操作,结果却是{"a": {"a": "e", "f": "g"}},将之前的值完全覆盖了,其实我想仍旧保留{"c":"d"}.
同时我也试了下单层结构json数据更新操作,完全没问题
另外我也使用了jsonb_set函数处理多层json数据,仍旧不能满足我的要求
解释:jsonb_set(target jsonb, path text[], new_value jsonb [, create_missing boolean])四个参数的含义
target:原json数据 path:新json数据期望在原json数据中的路径,不存在则新增,存在则修改,如{a,a} 第一个a表示原数据第一层key-a,第二个a表示原数据第二次key-a
new_value 期望插入/更新的json数据 create_missing:值为 true:如果元素值不存在,则添加;false:元素值不存在,不添加 (默认为true)
另外我也试了jsonb_set仅针对某一key进行单独的更新操作是可以成功的
进过上面的四轮测试,大致可以得出结论:pgsql官方提供的||操作和jsonb_set函数仅支持单层json格式数据的更新,无法实现我需求里面的多层json数据更新。
那么怎么实现最初的需求呢?思来想去,居然官方提供的方法或者函数只能实现单层json更新,也只能自定义函数来实现了--思路很简单,对原数据和新数据进行递归,一层层的更新。
下面贴出写的函数,基本能够满足上面的需求。各位大佬有更优方案也可以一起探讨。
关于pgsql function语法参考官方:pgsql create function
CREATE OR REPLACE FUNCTION jsonb_update(val1 JSONB,val2 JSONB) RETURNS JSONB AS $$ DECLARE result JSONB; v RECORD; BEGIN IF jsonb_typeof(val1) != 'null' THEN IF jsonb_typeof(val2) != 'null' THEN result = val1; FOR v IN SELECT key,value FROM jsonb_each(val2) LOOP IF jsonb_typeof(val1->v.key) != 'null' AND jsonb_typeof(val2->v.key) = 'object' AND jsonb_typeof(val1->v.key) = 'object' THEN result = result || jsonb_build_object(v.key, jsonb_update(val1->v.key, val2->v.key)); ELSE result = result || jsonb_build_object(v.key, v.value); END IF; END LOOP; RETURN result; ELSE RETURN val1; END IF; ELSE IF jsonb_typeof(val2) != 'null' THEN RETURN val2; ELSE RETURN result; END IF; END IF; END; $$ LANGUAGE plpgsql;
看下效果:
单层json格式数据更新:新的json格式是想要的效果
多层json格式数据更新:满足需求