Reputation: 129
I have a table, test
, in postgres 12 with a jsonb column, data_col
, that has many different keys and values.
My requirement is to select * from that table where value matches a string.
for example, the table has data as below
id some_value data_col
---------------------------------------------------------------
11 2018 {"a": "Old Farm"}
12 2019 {"b": "My house is old", "c": "See you tomorrow"}
13 2020 {"d": "The old house", "a": "Very Green", "e": "Olden days"}
As you can see, there are many different keys and so its not practical to lookup like the examples on the web suggests i.e col_name->>'Key'
I am looking to write a sql with a where clause to give me all rows that have the string "old" in it.
something like:
select * from test where data_col ILIKE '%old%'
should give me
11, 2018, Old Farm
12, 2019, My house is old
13, 2020, Olden days
Upvotes: 0
Views: 502
Reputation:
As you are using Postgres 12, you can use a SQL/JSON path function:
select id, some_value,
jsonb_path_query_first(data_col, '$.* ? (@ like_regex "old" flag "i")') #>> '{}'
from data
The #>>
operator is only there to convert the scalar JSON value into text (as there is no direct cast from jsonb
to text
that would remove the double quotes)
If there are potentially more values with the substring, you can use jsonb_path_query_array()
to all of them as an array (obviously you need to remove the #>>
then)
Upvotes: 0
Reputation: 222412
One option uses jsonb_each()
:
select t.*, x.*
from test t
cross join lateral jsonb_each(t.data_col) x
where x.value ilike '%old%'
Note that this multiplies the rows if an object contains "old" more than once. To avoid that, you can use exists
instead:
select t.*
from test t
where exists (
select 1
from jsonb_each(t.data_col) x
where x.val ilike '%old%'
)
Or if you want to aggregate all the matched values in one column:
select t.*, x.*
from test t
cross join lateral (
select string_agg(x.val, ',') as vals
from jsonb_each(t.data_col) x
where x.val ilike '%old%'
) x
where x.vals is not null
Upvotes: 1