There is currently no =
operator defined for the data type json
, because there is no well defined method to establish equality of the whole type.
You could cast to text
and use the =
operator then. This is short, but only works if your text representation matches and is unreliable.
Or you can unnest
the array and use the ->>
operator to .. get JSON object field as text
and compare individual fields.
Unfortunately, I cannot provide an SQL Fiddle, for some methods for arrays of json
are "not yet implemented" in JDBC. Try this at home (pg 9.3+):
Test table
2 rows: first one like in the question, second one with simple values.
CREATE TABLE t (
t_id int PRIMARY KEY
, jar json[]
);
INSERT INTO t VALUES
(1, '{"{\"value\" : \"03334/254146\", \"typeId\" : \"ea4e7d7e-7b87-4628-ba50-6a5f6e63dbf5\"}"
,"{\"value\" : \"03334/254147\", \"typeId\" : \"ea4e7d7e-7b87-4628-ba50-6a5f6e63dbf6\"}"
,"{\"value\" : \"03334/254148\", \"typeId\" : \"ea4e7d7e-7b87-4628-ba50-6a5f6e63dbf7\"}"}')
, (2, '{"{\"value\" : \"a\", \"typeId\" : \"x\"}"
,"{\"value\" : \"b\", \"typeId\" : \"y\"}"
,"{\"value\" : \"c\", \"typeId\" : \"z\"}"}');
Demos
Demo 1: you could use array_remove()
with text
representations (unreliable).
SELECT t_id
, jar, array_length(jar, 1) AS jar_len
, jar::text[] AS t, array_length(jar::text[], 1) AS t_len
,array_remove(jar::text[], '{"value" : "03334/254147", "typeId" : "ea4e7d7e-7b87-4628-ba50-6a5f6e63dbf6"}'::text) AS t_result
,array_remove(jar::text[], '{"value" : "03334/254147", "typeId" : "ea4e7d7e-7b87-4628-ba50-6a5f6e63dbf6"}'::text)::json[] AS j_result
FROM t;
Demo 2: unnest the array and test fields of individual elements.
SELECT t_id, array_agg(j) AS j_new
FROM t
, unnest(jar) AS j -- LATERAL JOIN
WHERE j->>'value' <> '03334/254146'
AND j->>'typeId' <> 'ea4e7d7e-7b87-4628-ba50-6a5f6e63dbf5'
GROUP BY 1;
Demo 3: alternative test with row type.
SELECT t_id, array_agg(j) AS j_new
FROM t
, unnest(jar) AS j -- LATERAL JOIN
WHERE (j->>'value', j->>'typeId') NOT IN (
('03334/254146', 'ea4e7d7e-7b87-4628-ba50-6a5f6e63dbf5')
,('a', 'x')
)
GROUP BY 1;
UPDATE as requested
Finally, this is how you could implement your UPDATE:
UPDATE t
SET jar = sub.jar
FROM (
SELECT t_id, array_agg(j) AS jar
FROM (SELECT t_id, jar FROM t WHERE t_id = 2) t -- reduce to relevant rows
, unnest(jar) AS j -- LATERAL JOIN
WHERE j->>'value' <> 'a'
AND j->>'typeId' <> 'x'
GROUP BY 1
) sub
WHERE t.t_id = sub.t_id;
More about the implicit LATERAL JOIN
:
How to turn json array into postgres array?
Query for element of array in JSON column (SO)
And about unnesting arrays:
How to preserve the original order of elements in an unnested array?
DB design
To simplify your situation consider an normalized schema: a separate table for the json
values (instead of the array column), joined in a n:1 relationship to the main table.
jsonb
in Postgres 9.4
You will be interested in the jsonb
data type in the upcoming Postgres 9.4 (link to devel manual). 'b' is for 'binary'. Among other things, there will be an equality operator =
for jsonb
. I expect most people will switch to jsonb
as soon as it's available.
Depesz blogged on jsonb.