Reputation: 303
I have a jsonb column that contains a dictionary which has a key that points to an array of string values. I need to query against that array.
The table (called "things") looks like this:
------------------
| my_column |
|----------------|
| { "a": ["X"] } |
------------------
I need to write two queries:
Does the array contain value "X"?
Does the array not contain value "X"?
my_column
has a non-null constraint, but it can contain an empty dictionary. The dictionary can also contain other key/value pairs.
The first query was easy:
SELECT * FROM things
WHERE my_column -> 'a' ? 'X';`
The second one is proving to be more challenging. I started there with:
SELECT * FROM things
WHERE NOT my_column -> 'a' ? 'X';
... but that excluded all the records that had dictionaries that didn't include key 'a'
. So I modified it like so:
SELECT * FROM things
WHERE my_column -> 'a' IS NULL OR NOT
my_column -> 'a' ? 'X';
This works, but is there a better way? Also, is it possible to index this query, and if so, how?
Upvotes: 1
Views: 1604
Reputation: 3970
I'm not sure if there's any better way -- that honestly looks pretty straightforward to me.
As for indexing, there are a couple things you can do.
First, you can index the jsonb field. Putting a GIN index on that field should help with any use of "exists"-type operators (like ?
).
If that isn't the solution you want for whatever reason, Postgres supports functional and partial indexes. A functional index might look like:
CREATE INDEX ON things ( my_column -> 'a' );
(note: It looks like postgres is having trouble with that syntax, which might be a bug. The concept holds, though.)
A partial index would get even more specific, and could even look like:
CREATE INDEX ON things (my_column)
WHERE my_column -> 'a' IS NULL OR NOT
my_column -> 'a' ? 'X';
Obviously, that won't help for more general queries.
At a guess, indexing the whole column with a GIN index is the right way to go, or at least the right place to start.
Upvotes: 1