【问题标题】:How to update JSON array with PostgreSQL如何使用 PostgreSQL 更新 JSON 数组
【发布时间】:2019-08-22 06:57:33
【问题描述】:

我有以下不便,我想仅使用 PostgreSQL 更新 JSON 数组的键。我有以下 json:

[
   {
      "ch":"1",
      "id":"12",
      "area":"0",
      "level":"Superficial",
      "width":"",
      "length":"",
      "othern":"5",
      "percent":"100",
      "location":" 2nd finger base"
   },
   {
      "ch":"1",
      "id":"13",
      "area":"0",
      "level":"Skin",
      "width":"",
      "length":"",
      "othern":"1",
      "percent":"100",
      "location":" Abdomen "
   }
]

如果 "othern" = X

,我需要将 "othern" 更新为另一个数字

(X 是我传递给查询的任何数字。例如,如果 othern = 5,则更新 othern)。

这个 JSON 可以更大,所以我需要可以在 JSON 数组中迭代并找到所有匹配 X 数字的 "othern" 并替换为新的一个。谢谢!

我已经尝试过使用 Postgresql 的这些函数 json,但我没有给出正确的结果:

    SELECT * FROM jsonb_to_recordset('[{"ch":"1", "id":"12", "area":"0", "level":"Superficial", "width":"", "length":"", "othern":"5", "percent":"100", "location":" 2nd finger base"}, {"ch":"1", "id":"13", "area":"0", "level":"Skin", "width":"", "length":"", "othern":"1", "percent":"100", "location":" Abdomen "}]'::jsonb) 
AS t (othern text);

我在 SQL 中发现这个函数与我需要的类似,但老实说 SQL 不是我的强项:

CREATE OR REPLACE FUNCTION "json_array_update_index"(
    "json"            json,
    "index_to_update" INTEGER,
    "value_to_update" anyelement
)
    RETURNS json
    LANGUAGE sql
    IMMUTABLE
    STRICT
AS $function$
SELECT concat('[', string_agg("element"::text, ','), ']')::json
FROM (SELECT CASE row_number() OVER () - 1
                 WHEN "index_to_update" THEN to_json("value_to_update")
                 ELSE "element"
                 END "element"
      FROM json_array_elements("json") AS "element") AS "elements"
$function$;


UPDATE plan_base
SET    atts = json_array_update_index([{"ch":"1", "id":"12", "area":"0", "level":"Superficial", "width":"", "length":"", "othern":"5", "percent":"100", "location":" 2nd finger base"}, {"ch":"1", "id":"13", "area":"0", "level":"Skin", "width":"", "length":"", "othern":"1", "percent":"100", "location":" Abdomen "}], '{"othern"}', '{"othern":"71"}'::json)
WHERE  id = 2;

【问题讨论】:

  • 好的,你传入一个数字。如果数字是 5,应该更新哪些元素?你的意思是:我能不能大点。这是什么意思?数组中的元素更多还是嵌套更深的元素?
  • @S-Man 如果我将它作为数字 5 传递,则所有字段(“othern”:“5”)必须更新为我也必须传递给查询的新数字。
  • @S-Man 更多类似这样的元素:[{ "ch":"1", "id":"13", "area":"0", "level":"Skin ", "width":"", "length":"", "othern":"1", "percent":"100", "location":"腹部" }, { "ch":"1", "id":"13", "area":"0", "level":"Skin", "width":"", "length":"", "othern":"1", "percent": “100”、“位置”:“腹部”}等]
  • 我仍然不清楚:您想找到所有包含 othern = 5 的元素。到目前为止,一切都很好。然后怎样呢?哪些元素应该更新为什么?也许您可以将复杂的示例更改为更简单的示例,每个元素只有两个字段并显示预期的输出
  • @S-Man 我想找到所有 "othern" = 5,并将它们自己更新为例如 "othern" = 7 , 仅使用 postgresql。

标签: arrays json postgresql updates


【解决方案1】:

您提供的函数更改 JSON 输入,发出更改后的 JSON 并并行更新表。

对于简单的更新,您不需要函数:

demo:db<>fiddle

UPDATE mytable
SET myjson = s.json_array
FROM (
    SELECT 
        jsonb_agg(
             CASE WHEN elems ->> 'othern' = '5' THEN
                 jsonb_set(elems, '{othern}', '"7"')
             ELSE elems  END
        ) as json_array
    FROM
        mytable,
        jsonb_array_elements(myjson) elems
) s
  1. jsonb_array_elements() 将数组扩展为每个元素一行
  2. jsonb_set() 更改其他字段的值。可以使用CASE 子句找到相关的 JSON 对象
  3. jsonb_agg() 再次将元素重新聚合到一个数组中。
  4. 此数组可用于更新您的列。

如果您确实需要一个获取参数并返回更改后的 JSON 的函数,那么这可能是一个解决方案。当然,这不会执行更新。我不太确定你是否想实现这一点:

demo:db<>fiddle

CREATE OR REPLACE FUNCTION json_array_update_index(_myjson jsonb, _val_to_change int, _dest_val int)
RETURNS jsonb
AS $$
DECLARE
    _json_output jsonb;
BEGIN
    SELECT 
        jsonb_agg(
             CASE WHEN elems ->> 'othern' = _val_to_change::text THEN
                 jsonb_set(elems, '{othern}', _dest_val::text::jsonb)
             ELSE elems  END
        ) as json_array
    FROM
        jsonb_array_elements(_myjson) elems
    INTO _json_output;

    RETURN _json_output;
END;
$$ LANGUAGE 'plpgsql';

如果您想像在问题中那样将两者结合起来,当然,您可以这样做:

demo:db<>fiddle

CREATE OR REPLACE FUNCTION json_array_update_index(_myjson jsonb, _val_to_change int, _dest_val int)
RETURNS jsonb
AS $$
DECLARE
    _json_output jsonb;
BEGIN
    UPDATE mytable
    SET myjson = s.json_array
    FROM (
        SELECT 
            jsonb_agg(
                 CASE WHEN elems ->> 'othern' = '5' THEN
                     jsonb_set(elems, '{othern}', '"7"')
                 ELSE elems  END
            ) as json_array
        FROM
            mytable,
            jsonb_array_elements(myjson) elems
    ) s
    RETURNING myjson INTO _json_output;

    RETURN _json_output;
END;
$$ LANGUAGE 'plpgsql';

【讨论】:

  • 优秀的答案,您不仅给了我解决问题的方法(update mytable 对我来说非常有效),而且您还教了我事情的原因. PD:我不知道 "CASE WHEN elems - >> etc" 部分,太好了!谢谢!
  • 我有个小不便,这个表的列保存为"JSON"类型。在我做了 "SELECT to_jsonb (myjson) ..." 之前,将其转换为 "JSONB" 从而进行更新的操作。现在我的问题是,我该如何返回 JSONB -> JSON 数据,从而将其保存到数据库中?谢谢
  • 重铸它:更新... SET myjson = json_array::json
  • json是用空格保存的,这样有没有不便?
  • 这就是我使用jsonb而不是jsonstackoverflow.com/questions/22654170/…的原因
猜你喜欢
  • 1970-01-01
  • 2020-08-22
  • 1970-01-01
  • 2012-12-22
  • 2020-07-19
  • 2020-04-07
  • 2017-11-02
  • 2017-01-13
  • 1970-01-01
相关资源
最近更新 更多