【问题标题】:plpgsql jsonb_set for JSON array of objects with nested arraysplpgsql jsonb_set 用于带有嵌套数组的 JSON 对象数组
【发布时间】:2021-11-24 05:11:24
【问题描述】:

使用 PostgreSQL 14.0 PL/SQL(在 do 块内)。尝试:

  1. 根据动态变量值(名为cty.cty_name)查询jsonb对象数组(依次具有对象+嵌套数组)中的某个键('county')
  2. 检索值并更改它
  3. 更新上述 jsonb 以反映 (2) 中的更新值
  4. 对多个值执行(3)后,创建新表,上面的jsonb为一行一列

步骤 (1) 和 (2) 正确执行。但是,就我的一生而言,我无法弄清楚 (3)。

jsonb object(res) -- 在索引根可能有100个数组项

[ {"county": "x", "dpa": ["a", "b", "c"]},
 {"county": "y", "dpa": ["d", "e", "f"]},
 {"county": "z", "dpa": ["h", "i", "j"]},
 ...
]

上面(1)和(2)的代码:

execute format('select jsonb_path_query_array(''%s'', ''$[*]?(@.%s=="%s")'')',
            res,'county',cty.cty_name) into s1;
execute format('select jsonb_array_elements(''%s'')->''%s''', s1,'dpa') into s2;
s2 := s2 || jsonb_build_array(r1.name);

在哪里说:

  • cty.cty_namey(由 select 中的 for loop 创建)
  • r1.namem

s2 保存新值,例如["d", "e", "f", "m"]

现在,要执行 (3) 我需要 pathdpa 的哪个键 countyres 的某个索引中的值 y 匹配。在jsonb_query_path 和 SQL/JSON 路径、美元引号字符串、jsonb_path_to_arrayformat 查询的双引号地狱、其他使用 idx 或 @987654343 的 SO 解决方案上尝试(但惨遭失败) @(但我的表中没有 JSON),我不得不求助于征求 Borg 集体的智慧。请帮忙。

【问题讨论】:

  • 你不会想听这个,但是don't use JSON for that
  • 哈哈.. @LaurenzAlbe 我鄙视 JSON。但是,输出应该是互联网前端的输入;这意味着 JSON 是最简单的设计选择。
  • 你不需要动态 SQL。

标签: postgresql plpgsql


【解决方案1】:

您在当前方法中遇到的问题是双重的:

  • 无法在体外“删除”匹配的县对象(通过 jsonb_set() 等)
  • 没有办法在 json 文档本身中强制唯一性(利用 ON CONFLICT ... DO UPDATE 机制)来完成相同的操作

当我们到达

现在,要执行 (3),我需要 dpa 的路径,其中关键县与 res 中某个索引中的值 y 匹配。

与其原地更新现有记录,不如直接删除匹配记录(“dpa”的值现在已经过时),重新聚合剩余的记录(即不匹配的对象),然后附加将匹配对象更新为聚合的 jsonb 数组,类似于:

SELECT jsonb_agg(a) || jsonb_build_object('county', 'y', 'dpa', (jsonb_path_query_array(res, '$[*] ? (@.county=="y")')#>'{0,dpa}') || jsonb_build_array('m') )
FROM jsonb_array_elements(res) a
WHERE NOT a @> (jsonb_path_query_array(res, '$[*] ? (@.county=="y")')->0);

这会根据您在 (4) 中的规范返回单个 jsonb 值;您应该能够根据需要将其参数化到您的 EXECUTE 调用中。

在输出顺序上值得注意的是,如果您正在循环初始“res”数组,那么数组中对象的顺序(相对于驱动光标的“county”值)将根据到您为“县”迭代的光标的顺序。

这是因为通过所述游标的完整循环将删除每个旧对象并在结果数组的末尾替换它们,因此如果相关,在此游标中定义 ORDER BY 子句将很重要。

【讨论】:

  • 非常感谢周到而彻底的回应。我将审查并实施建议的更改,并在未来几天返回时报告结果(仍然拒绝从 2022 年开始):-)
猜你喜欢
  • 1970-01-01
  • 2020-05-24
  • 2019-08-11
  • 2020-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多