I am writing a SQL query. It’s a very complex query. But here I in this question, I will only extract out the part that I am struggling to make it easier to explain what I am struggling with.
I have a jsonb readonly array column in the select statement of my query as follow.
SELECT column_1, column_2, json_agg(column_3)::jsonb as item_ids from items
Please pay attention to json_agg(column_3)::jsonb
.
The query return an array of text/ string for item_ids
column. If I want to filter if any of the given parameter or string is equal to any of the element/ value/ string in the item_ids
array, I can do something like this.
SELECT column_1, column_2, json_agg(column_3)::jsonb as item_ids from items
WHERE item_ids ? 'item_1'
That will return the row where any of the element of item_ids array is exactly equal to ‘item_1’.
But I want something like like operator and I want it to be case insensitive.
Metaphorically, something like this.
SELECT column_1, column_2, json_agg(column_3)::jsonb as item_ids from items
WHERE ANY(item_ids) ILIKE '%item_1%'
How can I do that?
The query returns the data in the following format.
column_1 | column_2 | item_ids
------------------------------------------------------
row1 col 1 | row1 col 2 | [ item_1, item_2, item_3 ]
row2 col 1 | row2 col 2 | [ item_1, item_2, item_3 ]
2
Answers
Finding something inside a json array is generally less performant than attempting to use standard sql operations on a table.
A viable option is to search for the existence of one such item among your data with an
EXISTS
operator. In this way, theWHERE
clause will filter out all group_id values that don’t have pattern at least once, and the json arrays you’ll be building are only the ones you need.Here’s an example:
On a side note, there are two problems with your queries:
GROUP BY
clauseWHERE
clause of the third query will apply before the aggregation is carried out, and for this reason, such clause does not make sense if you’re attempting to work on the computed jsonANY
only works on the right hand side, sovalue ILIKE ANY patterns
. There is no reversed operator where you could usepattern ??? ANY values
(unless you create yourself a custom operator), see Postgresql ILIKE/LIKE ANY returns no results when using a pattern. You will need to use a subquery in your condition, which is easier done with an actualtext[]
than ajsonb
holding an array of strings.You might be able to rewrite this into a
HAVING
condition depending on how exactly your aggregation works.Alternatively, if you’re dead-set on using a
jsonb
value, you can use a json path query with thelike_regex
operator: