在 postgreSQL 中用逗号分隔连接 jsonb 元素

Concatenation of jsonb elements in postgreSQL with comma separation

我想设计一个查询,我可以在其中以受控方式将两个 jsonb 与 postgreSQL 中的未知 number/set 元素组合起来。 jsonb 运算符 || 几乎完全符合我的目的,但对于其中一个 jsonb 元素,我想用逗号连接和分隔两个值,而不是让第二个 jsonb 的值覆盖第一个的值。例如:

'{"a":"foo", "b":"one", "special":"comma"}'::jsonb || '{"a":"bar", "special":"separated"}'::jsonb → '{"a":"bar", "b":"one", "special":"comma,separated"}'

我当前的查询如下:

INSERT INTO table AS t (col1, col2, col3_jsonb)
VALUES ("first", "second", '["a":"bar", "special":"separated"]'::jsonb))
ON CONFLICT ON CONSTRAINT unique_entries DO UPDATE
SET col3_jsonb = excluded.col3_jsonb || t.col3_jsonb
RETURNING id;

这导致 col3_jsonb 的 jsonb 元素的值 special 设置为 separated 而不是所需的 comma,separated。我知道这是按照记录工作的串联运算符,但我不确定如何以不同的方式处理 jsonb 的一个元素,而不是尝试在查询的其他地方使用 WITH.. 子句提取特殊值。任何见解或提示将不胜感激!

您可以使用 jsonb_each on the two values followed by jsonb_object_agg 将它们放回对象中:

…
SET col3_jsonb = (
 SELECT jsonb_object_agg(
    key,
    COALESCE(to_jsonb((old.value->>0) || ',' || (new.value->>0)), new.value, old.value)
  )
  FROM jsonb_each(example.old_obj) old
  FULL OUTER JOIN jsonb_each(example.new_obj) new USING (key)
)

(online demo)

将任意 JSON 值转换为所需的可连接字符串 a trick。如果您知道所有对象属性都有字符串值,则可以使用 jsonb_each_text 来简化:

  SELECT jsonb_object_agg(
    key,
    COALESCE(old.value || ',' || new.value, new.value, old.value)
  )
  FROM jsonb_each_text(example.old_obj) old
  FULL OUTER JOIN jsonb_each_text(example.new_obj) new USING (key)
with t(a,b) as (values(
    '{"a":"foo", "b":"one", "special":"comma"}'::jsonb,
    '{"a":"bar", "special":"separated"}'::jsonb))
select
    a || jsonb_set(b, '{special}',
        to_jsonb(concat_ws(',', nullif(a->>'special', ''), nullif(b->>'special', ''))))
from t;
┌────────────────────────────────────────────────────────┐
│                        ?column?                        │
├────────────────────────────────────────────────────────┤
│ {"a": "bar", "b": "one", "special": "comma,separated"} │
└────────────────────────────────────────────────────────┘

nullif()concat_ws() 函数需要一个或两个 "special" 值是 missing/null/empty

的情况