在 JSONB 数组中插入元素 - Postgresql
Insert element in JSONB Array - Postgresql
假设我有一个 table:
SELECT * FROM settings;
| id | name | strategies |
| -- | --- | --- |
| 1 | default | [{name: xyz, enabled: true}, {name: bot2, enabled: true}] |
| 2 | new1 | [{name: bot2, enabled: true}, {name: xyz, enabled: false}] |
我想在 bot2
之前添加一个新对象 {name: bot1, enabled: true}
。
我正在尝试使用来自 的解决方案:
WITH bot2_index AS (SELECT
pos- 1 AS bot2_index
FROM
settings,
jsonb_array_elements(strategies) WITH ordinality arr(elem, pos)
WHERE
NAME = 'default'
AND elem->>'name' = 'bot2')
UPDATE settings
SET strategies = jsonb_set(strategies, '{bot2_index}', '{
"name": "bot1",
"enabled": false
}', TRUE);
但我明白了
ERROR: path element at position 1 is not an integer: "bot2_index"
bot2_index
的类型是 bigint
那么为什么这个语法不起作用?
我还尝试了其他变体,例如 bot2_index
、bot2_index::int
、bot2_index::string
,甚至 运行 将其作为两个单独的查询(就像在接受的答案中一样) ) 但它也不起作用。
编辑#1
此语法有效,但它似乎替换了该索引处的元素,而不是在给定索引处的元素之前或之后附加元素 - 我如何才能使其像 JS splice()
函数一样工作?
UPDATE settings
SET strategies = jsonb_set(strategies, concat('{',(SELECT
pos- 1 AS bot2_index
FROM
settings,
jsonb_array_elements(strategies) WITH ordinality arr(elem, pos)
WHERE
NAME = 'default'
AND elem->>'name' = 'js:bot2'),'}')::text[], '{
"name": "bot1",
"enabled": false
}', TRUE);
首先,对于您当前的查询,您应该像下面这样使用它:
WITH bot2_index AS (SELECT
pos- 1 AS bot2_index
FROM
settings,
jsonb_array_elements(strategies) WITH ordinality arr(elem, pos)
WHERE
name = 'default'
AND elem->>'name' = 'bot2')
UPDATE settings
SET strategies = jsonb_set(strategies, array[bot2_index::text], '{
"name": "bot1",
"enabled": false
}'::jsonb, false) from bot2_index;
但查询将替换现有的
DEMO
您应该使用 jsonb_insert
而不是 jsonb_set
。
WITH bot2_index AS (SELECT
pos- 1 AS bot2_index
FROM
settings,
jsonb_array_elements(strategies) WITH ordinality arr(elem, pos)
WHERE
name = 'default'
AND elem->>'name' = 'bot2')
UPDATE settings
SET strategies = jsonb_insert(strategies, array[bot2_index::text], '{
"name": "bot1",
"enabled": false
}'::jsonb, false) from bot2_index;
假设我有一个 table:
SELECT * FROM settings;
| id | name | strategies |
| -- | --- | --- |
| 1 | default | [{name: xyz, enabled: true}, {name: bot2, enabled: true}] |
| 2 | new1 | [{name: bot2, enabled: true}, {name: xyz, enabled: false}] |
我想在 bot2
之前添加一个新对象 {name: bot1, enabled: true}
。
我正在尝试使用来自
WITH bot2_index AS (SELECT
pos- 1 AS bot2_index
FROM
settings,
jsonb_array_elements(strategies) WITH ordinality arr(elem, pos)
WHERE
NAME = 'default'
AND elem->>'name' = 'bot2')
UPDATE settings
SET strategies = jsonb_set(strategies, '{bot2_index}', '{
"name": "bot1",
"enabled": false
}', TRUE);
但我明白了
ERROR: path element at position 1 is not an integer: "bot2_index"
bot2_index
的类型是 bigint
那么为什么这个语法不起作用?
我还尝试了其他变体,例如 bot2_index
、bot2_index::int
、bot2_index::string
,甚至 运行 将其作为两个单独的查询(就像在接受的答案中一样) ) 但它也不起作用。
编辑#1
此语法有效,但它似乎替换了该索引处的元素,而不是在给定索引处的元素之前或之后附加元素 - 我如何才能使其像 JS splice()
函数一样工作?
UPDATE settings
SET strategies = jsonb_set(strategies, concat('{',(SELECT
pos- 1 AS bot2_index
FROM
settings,
jsonb_array_elements(strategies) WITH ordinality arr(elem, pos)
WHERE
NAME = 'default'
AND elem->>'name' = 'js:bot2'),'}')::text[], '{
"name": "bot1",
"enabled": false
}', TRUE);
首先,对于您当前的查询,您应该像下面这样使用它:
WITH bot2_index AS (SELECT
pos- 1 AS bot2_index
FROM
settings,
jsonb_array_elements(strategies) WITH ordinality arr(elem, pos)
WHERE
name = 'default'
AND elem->>'name' = 'bot2')
UPDATE settings
SET strategies = jsonb_set(strategies, array[bot2_index::text], '{
"name": "bot1",
"enabled": false
}'::jsonb, false) from bot2_index;
但查询将替换现有的 DEMO
您应该使用 jsonb_insert
而不是 jsonb_set
。
WITH bot2_index AS (SELECT
pos- 1 AS bot2_index
FROM
settings,
jsonb_array_elements(strategies) WITH ordinality arr(elem, pos)
WHERE
name = 'default'
AND elem->>'name' = 'bot2')
UPDATE settings
SET strategies = jsonb_insert(strategies, array[bot2_index::text], '{
"name": "bot1",
"enabled": false
}'::jsonb, false) from bot2_index;