Postgres jsonb 'NOT contains' operator

This can be achieved with several conditions. It's not elegant but I didn't find another way to do so.

So, first, get every row which simple don't have 'City' attribute and then add 'OR' condition to check for correct field value.

select count(*) from jsonbtest where 
  NOT(attributes ? 'City') 
  OR (attributes ? 'City') is NULL -- this is required if attributes can be null
  OR (attributes->>'City' != 'Mesa')) 

---contains specific key (City), does not contain value ('"Mesa"').

SELECT count(*) FROM jsonbtest  WHERE NOT (attributes  -> 'City'  @> '"Mesa"');

---does not contain specific key value pair: {"City":"Mesa"}

SELECT count(*) FROM jsonbtest  WHERE  NOT (attributes  @> '{"City":"Mesa"}')

Since attributes key can be others except City. So these two queries are different!


Two way, you can test any json(b) value

  • the ->> operator extract value as text. But this operation slow, if you will use the value only test
  • the @> operator test any json(b) contain any json(b). This is a quick but you are not tested NOT option.

Simply and quick way:

NOT (attribute @> '{"City":"Mesa"}'::jsonb)

I've change attribute->>'City' <> 'Mesa' to NOT (attribute @> '{"City":"Mesa"}'::jsonb) and my ~2.000.000 rows query result time changed 45secs to 25secs.