Remove multiple keys from jsonb column in one statement
That should be as simple as applying the #-
operator multiple times:
SELECT '{ "a": 1, "b": 2, "c": 3 }'::jsonb #- '{a}' #- '{b}';
?column?
----------
{"c": 3}
(1 row)
Remove multiple key/value pairs in one postgresql statement
(a) You cant't mix jsonb type with array type : column::jsonb - ARRAY(...)
is not allowed.
(b) If you want to remove several key/value pairs from the same jsonb data, then you have to create a user-defined aggregate
based on the jsonb #-
operator :
CREATE OR REPLACE FUNCTION jsonb_remove(x jsonb, y jsonb, p text[])
RETURNS jsonb LANGUAGE sql IMMUTABLE AS
$$ SELECT COALESCE(x, y) #- p ; $$ ;
DROP AGGREGATE IF EXISTS jsonb_remove_agg(jsonb, text[]) ;
CREATE AGGREGATE jsonb_remove_agg(jsonb, text[])
( sfunc = jsonb_remove
, stype = jsonb
) ;
Then you can iterate on the new aggregate within a query :
UPDATE template as w
SET
column = l.elements
FROM
( SELECT id -- id is to be replaced by the primary key of table template
, jsonb_remove_agg(column, array['headers', wf.elements]) as elements
FROM template
CROSS JOIN LATERAL jsonb_object_keys(column->'headers') as wf(elements)
WHERE LOWER(wf.elements) LIKE ANY(ARRAY['%authorization%','%token%','%apikey%'])
GROUP BY id -- id is to be replaced by the primary key of table template
) AS l
WHERE w.id = l.id ; -- -- id is to be replaced by the primary key of table template
see the test result in dbfiddle.
How to delete an array of keys from a Postgres jsonb object?
Use the -
operator with an array of text
on the right hand side:
SELECT '{"foo": true, "bar": false, "baz": true}'::jsonb
- '{foo,bar}'::text[];
Remove key from multiple nested jsonb objects with unknown keys in PostgreSQL
The structure of the json column is an anti-pattern, I fully agree with the comment by @mvp:
... you should consider extracting your data from json and store it in real SQL table(s) instead.
If you are forced to play with the original data, use the function:
create or replace function remove_nested_object(obj jsonb, key_to_remove text)
returns jsonb language sql immutable as $$
select jsonb_object_agg(key, value- key_to_remove)
from jsonb_each(obj)
$$;
update my_table
set json_column = remove_nested_object(json_column, 'toDelete')
where json_column::text like '%"toDelete":%';
Remove long key value pairs in jsonb column in postgres with SQL
There is no built-in function for this. You will need to write your own.
Something along the lines:
create function remove_long_values(p_input jsonb, p_maxlen int)
returns jsonb
as
$$
select coalesce(jsonb_object_agg(e.ky, e.val), '{}')
from jsonb_each(p_input) as e(ky,val)
where length(e.val::text) <= p_maxlen;
$$
language sql
immutable
parallel safe;
The above does not deal with nested key/value pairs! It only checks this on the first level.
Then use it in the query:
CREATE MATERIALIZED VIEW IF NOT EXISTS test_materialized_view
AS
SELECT t1.id, t1.data1 || t1.data2 || remove_long_values(t2.data1,250) as "data"
FROM table_1 t1
LEFT JOIN table_2 t2 ON (...);
PostgreSQL jsonb - omit multiple nested keys
There is no way to shorten the expression. If your goal is to pass to the query a single array of keys to be deleted you can use jsonb_set()
with jsonb_each()
:
with my_table(json_col) as (
values
(jsonb '{"a": {"b":1, "c": 2, "d": 3}}')
)
select jsonb_set(json_col, '{a}', jsonb_object_agg(key, value))
from my_table
cross join jsonb_each(json_col->'a')
where key <> all('{b, d}') -- input
group by json_col -- use PK here if exists
jsonb_set
-----------------
{"a": {"c": 2}}
(1 row)
The solution is obviously more expensive but may be handy when dealing with many keys to be deleted.
Remove multiple keys and values with its nested dictionary then arrange keys in this “0”,“1”,“2”,“3” order like it was before in Python
Solution for multiple keys to remove:
dct = {
"0": {"course": "CSE", "password": "Amsal", "username": "1800101253"},
"1": {"course": "CSE", "password": "Amsal2", "username": "1800101253"},
"2": {"course": "CSE", "password": "Amsal3", "username": "1800101253"},
"3": {"course": "CSE", "password": "Amsal4", "username": "1800101253"},
"4": {"course": "CSE", "password": "fjfjgal", "username": "1800101255"},
"5": {"course": "CSE", "password": "Amsal", "username": "1804959494"},
"Total": 6,
}
to_remove = [0, 1, 2, 3]
lst = [dct[str(v)] for v in range(dct["Total"]) if v not in to_remove]
dct = {str(i): v for i, v in enumerate(lst)}
dct["Total"] = len(lst)
print(dct)
Prints:
{'0': {'course': 'CSE', 'password': 'fjfjgal', 'username': '1800101255'},
'1': {'course': 'CSE', 'password': 'Amsal', 'username': '1804959494'},
'Total': 2}
Or: To remove according username
:
username_to_remove = "1800101253"
lst = [
dct[str(v)]
for v in range(dct["Total"])
if dct[str(v)]["username"] != username_to_remove
]
dct = {str(i): v for i, v in enumerate(lst)}
dct["Total"] = len(lst)
PostgreSQL: Remove attribute from JSON column
Update: for 9.5+, there are explicit operators you can use with jsonb
(if you have a json
typed column, you can use casts to apply a modification):
Deleting a key (or an index) from a JSON object (or, from an array) can be done with the -
operator:
SELECT jsonb '{"a":1,"b":2}' - 'a', -- will yield jsonb '{"b":2}'
jsonb '["a",1,"b",2]' - 1 -- will yield jsonb '["a","b",2]'
Deleting, from deep in a JSON hierarchy can be done with the #-
operator:
SELECT '{"a":[null,{"b":[3.14]}]}' #- '{a,1,b,0}'
-- will yield jsonb '{"a":[null,{"b":[]}]}'
For 9.4, you can use a modified version of the original answer (below), but instead of aggregating a JSON string, you can aggregate into a json
object directly with json_object_agg()
.
Related: other JSON manipulations whithin PostgreSQL:
- How do I modify fields inside the new PostgreSQL JSON datatype?
Original answer (applies to PostgreSQL 9.3):
If you have at least PostgreSQL 9.3, you can split your object into pairs with json_each()
and filter your unwanted fields, then build up the json again manually. Something like:
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
With 9.2 (or lower) it is not possible.
Edit:
A more convenient form is to create a function, which can remove any number of attributes in a json
field:
Edit 2: string_agg()
is less expensive than 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$;
With this function, all you need to do is to run the query below:
UPDATE my_table
SET data = json_object_delete_keys(data, 'attrB');
Related Topics
How to Modify Query to Remove Double-Quotes from All Columns
Addition of Total Hours in SQL Server
The Network Adapter Could Not Establish the Connection in SQL Developer
Sql Server How to Find the Customers Who Have Bought a Product from Each Store
Regex Pattern Inside SQL Replace Function
Comma Separated Values in SQL Server Returning Duplicates
Error Code 1292 Incorrect Date Value MySQL
Sql - How to Sum/Aggregate Certain Rows in a Table
Simulating group_concat MySQL Function in Microsoft SQL Server 2005
How to Store Multiple Values in Single Field in SQL Database
Insert Value into Table If Conidition Is Met At Least One Time
Find All Parent Records Where All Child Records Have a Given Value (But Not Just Some Child Records)
Laravel Eloquent Mutiple Counts With Different Conditions in One Query
Select Rows Within Last Complete Minute
Get Count of Records in Every Hour in the Last 24 Hour
Find Out Count of Employees Joined in January Month
Sql Server:How to Test If a String Has Only Digit Characters