PostgreSQL 没有提供直接可用的 JSON 内嵌数组的修改操作。通过将一些 JSON 实用函数与数组函数结合使用,您可以构造动态更新语句,来执行按值添加/删除数组元素的操作。
示例
让我们创建一个简单的 user 表,其中包含 id、username 和 metadata 属性,metadata 属性的类型为 jsonb:
CREATE TABLE users (
id serial PRIMARY KEY,
username TEXT NOT NULL,
meta_data JSONB NOT NULL DEFAULT '{}'::jsonb
);
INSERT INTO users (username, meta_data)
VALUES ('johndoe', '{"roles": ["hr", "marketing", "sales"]}'::jsonb);
SELECT id, username, meta_data FROM users;
输出结果为:
id | username | meta_data
----+----------+-----------------------------------------
1 | johndoe | {"roles": ["hr", "marketing", "sales"]}
(1 row)
添加元素
让我们将 “development” 和 “administration” 角色添加到用户的 roles 数组中:
UPDATE users
SET meta_data = jsonb_set(meta_data, ARRAY['roles'],
COALESCE(meta_data->'roles', '[]'::jsonb) ||
array_to_json(ARRAY['development', 'administration'])::jsonb)
WHERE id = 1;
添加相当简单。函数jsonb_set将要更新的 json 结构作为第一个参数,将一个指向要更新的部分的标识符/索引的 PostgreSQL 数组作为第二个参数,将新值作为第三个参数。您甚至可以通过数组下标,定位到用户的第一个角色,并将其替换为新值:
UPDATE users
SET meta_data = jsonb_set(meta_data, '{roles,0}', '"administration"'::jsonb)
WHERE id = 1;
删除元素
删除一个角色会稍微复杂一些:
UPDATE users
SET meta_data = jsonb_set(meta_data, ARRAY['roles'],
array_to_json(
array(
SELECT arr.elem
FROM jsonb_array_elements(meta_data->'roles')
WITH ordinality arr(elem, position)
WHERE arr.elem != '"administration"'::jsonb)
)::jsonb)
WHERE id = 1;
我们可以使用jsonb_array_elements函数,将 JSON 数组转换为行集合。然后可以用普通的 WHERE 条件对行集合进行过滤。在过滤后,将结果集传递给array()构造函数,转换回数组。之后,我们可以对新的数组应用array_to_json函数,将其转换回 JSON 数组。