我需要从json类型列中删除一些属性。
表:
CREATE TABLE my_table( id VARCHAR(80), data json);
INSERT INTO my_table (id, data) VALUES (
'A',
'{"attrA":1,"attrB":true,"attrC":["a", "b", "c"]}'
);
现在,我需要从列attrB
中删除data
。
像alter table my_table drop column data->'attrB';
这样的东西会很好。但是使用临时表的方法也足够了。
答案 0 :(得分:64)
更新:对于9.5+,您可以使用jsonb
显式运算符(如果您有json
类型列,则可以使用强制转换来应用修改):
可以使用-
运算符从JSON对象(或从数组中)删除键(或索引):
SELECT jsonb '{"a":1,"b":2}' - 'a', -- will yield jsonb '{"b":2}'
jsonb '["a",1,"b",2]' - 1 -- will yield jsonb '["a","b",2]'
可以使用#-
运算符从JSON层次结构中深入删除:
SELECT '{"a":[null,{"b":[3.14]}]}' #- '{a,1,b,0}'
-- will yield jsonb '{"a":[null,{"b":[]}]}'
对于9.4,您可以使用原始答案的修改版本(下面),但不是聚合JSON字符串,而是可以直接使用json
聚合到json_object_agg()
对象。
相关:PostgreSQL中的其他JSON操作:
原始回答(适用于PostgreSQL 9.3):
如果您至少拥有PostgreSQL 9.3,则可以将对象与json_each()
成对分割并过滤掉不需要的字段,然后再次手动构建json。类似的东西:
SELECT data::text::json AS before,
('{' || array_to_string(array_agg(to_json(l.key) || ':' || l.value), ',') || '}')::json AS after
FROM (VALUES ('{"attrA":1,"attrB":true,"attrC":["a","b","c"]}'::json)) AS v(data),
LATERAL (SELECT * FROM json_each(data) WHERE "key" <> 'attrB') AS l
GROUP BY data::text
9.2(或更低)是不可能的。
修改强>:
更方便的形式是创建一个函数,可以删除json
字段中的任意数量的属性:
修改2 :string_agg()
比array_to_string(array_agg())
便宜
CREATE OR REPLACE FUNCTION "json_object_delete_keys"("json" json, VARIADIC "keys_to_delete" TEXT[])
RETURNS json
LANGUAGE sql
IMMUTABLE
STRICT
AS $function$
SELECT COALESCE(
(SELECT ('{' || string_agg(to_json("key") || ':' || "value", ',') || '}')
FROM json_each("json")
WHERE "key" <> ALL ("keys_to_delete")),
'{}'
)::json
$function$;
使用此功能,您只需运行以下查询:
UPDATE my_table
SET data = json_object_delete_keys(data, 'attrB');
答案 1 :(得分:34)
使用JSONB类型的PostgreSQL 9.5变得更加容易。请参阅记录here的JSONB运算符。
您可以使用&#34; - &#34;删除顶级属性操作
SELECT '{"a": {"key":"value"}, "b": 2, "c": true}'::jsonb - 'a'
// -> {"b": 2, "c": true}
您可以在更新调用中使用它来更新现有的JSONB字段。
UPDATE my_table SET data = data - 'attrB'
如果在函数中使用,您还可以通过参数动态提供属性名称。
CREATE OR REPLACE FUNCTION delete_mytable_data_key(
_id integer,
_key character varying)
RETURNS void AS
$BODY$
BEGIN
UPDATE my_table SET
data = data - _key
WHERE id = _id;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
反向运算符是&#34; ||&#34;,以便将两个JSONB数据包连接在一起。请注意,该属性的最右侧使用将覆盖之前的任何属性。
SELECT '{"a": true, "c": true}'::jsonb || '{"a": false, "b": 2}'::jsonb
// -> {"a": false, "b": 2, "c": true}
答案 2 :(得分:3)
这是一个丑陋的黑客,但如果attrB
不是你的第一把钥匙而且它只出现一次那么你可以做以下事情:
UPDATE my_table SET data = REPLACE(data::text, ',"attrB":' || (data->'attrB')::text, '')::json;
答案 3 :(得分:2)
我无法让SELECT '{"a": "b"}'::jsonb - 'a';
在9.5.2中工作。但是,SELECT '{"a": "b"}'::jsonb #- '{a}';
确实有效!
答案 4 :(得分:2)
虽然使用jsonb运算符在9.5+中肯定更容易,但是pozs为删除多个键而编写的函数仍然很有用。例如,如果要删除的键存储在表中,则可以使用该函数将它们全部删除。这是一个更新的函数,使用jsonb和postgresql 9.5 +:
CREATE FUNCTION remove_multiple_keys(IN object jsonb,
variadic keys_to_delete text[],
OUT jsonb)
IMMUTABLE
STRICT
LANGUAGE SQL
AS
$$
SELECT jsonb_object_agg(key, value)
FROM (SELECT key, value
FROM jsonb_each("object")
WHERE NOT (key = ANY("keys_to_delete"))
) each_subselect
$$
;
如果要删除的键存储在一个表中,(例如在表&#34;键&#34;表&#34; table_with_keys&#34;)中,您可以像这样调用此函数:
SELECT remove_multiple_keys(my_json_object,
VARIADIC (SELECT array_agg(keys) FROM table_with_keys));
答案 5 :(得分:1)
另一种方便的方法是使用hstore扩展名。这样你就可以编写一些更方便的函数来设置/删除json对象中的键。我想出了以下功能来做同样的事情:
CREATE OR REPLACE FUNCTION remove_key(json_in json, key_name text)
RETURNS json AS $$
DECLARE item json;
DECLARE fields hstore;
BEGIN
-- Initialize the hstore with desired key being set to NULL
fields := hstore(key_name,NULL);
-- Parse through Input Json and push each key into hstore
FOR item IN SELECT row_to_json(r.*) FROM json_each_text(json_in) AS r
LOOP
--RAISE NOTICE 'Parsing Item % %', item->>'key', item->>'value';
fields := (fields::hstore || hstore(item->>'key', item->>'value'));
END LOOP;
--RAISE NOTICE 'Result %', hstore_to_json(fields);
-- Remove the desired key from store
fields := fields-key_name;
RETURN hstore_to_json(fields);
END;
$$ LANGUAGE plpgsql
SECURITY DEFINER
STRICT;
一个简单的使用示例是:
SELECT remove_key(('{"Name":"My Name", "Items" :[{ "Id" : 1, "Name" : "Name 1"}, { "Id" : 2, "Name 2" : "Item2 Name"}]}')::json, 'Name');
-- Result
"{"Items": "[{ \"Id\" : 1, \"Name\" : \"Name 1\"}, { \"Id\" : 2, \"Name 2\" : \"Item2 Name\"}]"}"
我还有另一个函数来执行set_key操作以及以下操作:
CREATE OR REPLACE FUNCTION set_key(json_in json, key_name text, key_value text)
RETURNS json AS $$
DECLARE item json;
DECLARE fields hstore;
BEGIN
-- Initialize the hstore with desired key value
fields := hstore(key_name,key_value);
-- Parse through Input Json and push each key into hstore
FOR item IN SELECT row_to_json(r.*) FROM json_each_text(json_in) AS r
LOOP
--RAISE NOTICE 'Parsing Item % %', item->>'key', item->>'value';
fields := (fields::hstore || hstore(item->>'key', item->>'value'));
END LOOP;
--RAISE NOTICE 'Result %', hstore_to_json(fields);
RETURN hstore_to_json(fields);
END;
$$ LANGUAGE plpgsql
SECURITY DEFINER
STRICT;
我在blog这里已经讨论了更多。
答案 6 :(得分:0)
我一直在努力寻找一个简单的更新查询,该查询在不创建函数的情况下删除了Postgres 9.4中的json键,因此这是@posz答案的更新。
UPDATE someTable t
SET someField = newValue
FROM (
SELECT id,
json_object_agg(l.key, l.value)::text AS newValue
FROM someTable t,
LATERAL (
SELECT *
FROM json_each(t.someField::json)
WHERE "key" <> ALL (ARRAY['key1', 'key2', 'key3'])
) AS l
GROUP BY id
) upd
WHERE t.id = upd.id
查询假设您有一个这样的表:
CREATE TABLE myTable (
id SERIAL PRIMARY KEY,
someField text
);
我想您可以使用@posz答案中的这一行代替json_object_agg行,以使其在较旧的postgres上运行,但我没有对其进行测试。
('{' || array_to_string(array_agg(to_json(l.key) || ':' || l.value), ',') || '}')::json AS after
还要确保从子请求中运行select,以确保您要更新正确的数据
答案 7 :(得分:0)
只需使用#-
运算符,例如:
SELECT '{"foo": 10, "bar": [], "baz": {}}'::jsonb #- '{baz}';
答案 8 :(得分:0)
如果您不仅要从单个文档而且要从数组中删除 JSON 属性,请考虑使用如下语句:
UPDATE table_to_update t
SET jsonColumnWithArray = (SELECT JSON_AGG(jsonItem)
FROM (SELECT JSON_ARRAY_ELEMENTS(t1.jsonColumnWithArray)::JSONB #- '{customerChange, oldPeriod}' AS jsonItem
FROM table_to_update t1
WHERE t1.id = t1.id) AS t2);
输入
[
{
"customerChange": {
"newPeriod": null,
"oldPeriod": null
}
},
{
"customerChange": {
"newPeriod": null,
"oldPeriod": null
}
}
]
输出
[
{
"customerChange": {
"newPeriod": null
}
},
{
"customerChange": {
"newPeriod": null
}
}
]