My table:
CREATE TABLE items (
id BIGINT PRIMARY KEY NOT NULL,
name VARCHAR,
images json
);
images format:
[
{
"id": "owner",
"full": "<url>",
"thumb": "<url>"
},
{
"id": "note_0",
"full": "<url>",
"thumb": "<url>"
},
{
"id": "note_1",
"full": "<url>",
"thumb": "<url>"
},
{
"id": "note_2",
"full": "<url>",
"thumb": "<url>"
}
]
I need something like this:
UPDATE items SET images = delete(images, 'note_1');
1 Answer 1
To remove all elements from the column images
(holding a json array) where 'id'
is 'note_1'
:
pg 9.3
UPDATE items i
SET images = i2.images
FROM (
SELECT id, array_to_json(array_agg(elem)) AS images
FROM items i2
, json_array_elements(i2.images) elem
WHERE elem->>'id' <> 'note_1'
GROUP BY 1
) i2
WHERE i2.id = i.id
AND json_array_length(i2.images) < json_array_length(i.images);
Explain
- Unnest the JSON array with
json_array_elements()
in a subquery using an implicitJOIN LATERAL
for the set-returning function. Details: - JOIN to the base table and add another
WHERE
condition usingjson_array_length()
to exclude unaffected rows - so you don't update each and every row of the table, which would be expensive (and wide-spread) nonsense.
pg 9.4
This gets much easier with jsonb
and additional jsonb
operators.
UPDATE items i
SET images = i2.images
FROM (
SELECT id, array_to_json(array_agg(elem)) AS images
FROM items cand
, json_array_elements(cand.images) elem
WHERE cand.images @> '{[{"id":"note_1"}]}'::jsonb
AND elem->>'id' <> 'note_1'
GROUP BY 1
) i2
WHERE i2.id = i.id;
Eliminates unaffected rows at the start, which is much faster. Plus, there is extensive native index support for jsonb
, too, now.
Here are some example, benchmarks and comparison of new features to old json and MongoDB, plus outlook to jsquery by (some of) their main authors, Alexander Korotkov, Oleg Bartunov andTeodor Sigaevat PGCon 2014:
-
what does items cand meanCommonSenseCode– CommonSenseCode2018年08月29日 17:20:37 +00:00Commented Aug 29, 2018 at 17:20
-
@commonSenseCode:
FROM items cand
is short syntax forFROM items AS cand
-cand
is a table alias. TheAS
keyword is safe to omit for table aliases (as opposed to column aliases). See: dba.stackexchange.com/a/61455/3684 or stackoverflow.com/a/11543614/939860Erwin Brandstetter– Erwin Brandstetter2018年09月02日 01:37:05 +00:00Commented Sep 2, 2018 at 1:37 -
2
-
The 9.3 version (at least) doesn't appear to work if you're removing the last item from an array?toxaq– toxaq2020年09月17日 05:07:16 +00:00Commented Sep 17, 2020 at 5:07
'{"id":"note_1"}'
or delete any element from the array that has'note_1'
as key or value?{"id": "note_1", "full": "<url>", "thumb": "<url>"}
where id = "note_1"