1

I want to get all records where any value in jsonb field contains a text regardless of key.

For example: field contains json {k1: 'hello', k2: 'world'}. I want to get this record by the text 'hello'. I don't care about keys or any json structure, only values.

One dirty hack is to cast the field to varchar where jsonb_field::varchar like ..., but this is ugly and it will match keys and {} as well.

Another dirty hack looks like this:

SELECT * FROM mytable AS m1 WHERE (
  SELECT string_agg(value, '') FROM jsonb_each_text( (SELECT name FROM mytable AS m2 WHERE m1.id= m2.id)::jsonb ) 
) LIKE '%whatever%';

but it's ugly too.

How can I do this?

Oleg Antonyan
  • 2,943
  • 3
  • 28
  • 44

1 Answers1

3

For simple JSONs you can use more appropriate query like

select * 
from mytable t 
where exists (
  select 1 
  from jsonb_each_text(t.jsonbfield) j 
  where j.value = 'hello');

It works fine for JSONs like in your example but not helps for more complex JSONs like {"a":"hello","b":1,"c":{"c":"world"}}

I can propose to create the stored function like

create or replace function jsonb_enum_values(in jsonb) returns setof varchar as $$
begin
  case jsonb_typeof($1)
    when 'object' then
      return query select jsonb_enum_values(j.value) from jsonb_each($1) j;
    when 'array' then
      return query select jsonb_enum_values(a) from jsonb_array_elements($1) as a;
    else
      return next $1::varchar;
  end case;
end
$$ language plpgsql immutable;

to list all values including recursive objects (It is up to you what to do with arrays).

Here is usage example:

with t(x) as (
  values
    ('{"a":"hello","b":"world","c":1,"d":{"e":"win","f":"amp"}}'::jsonb),
    ('{"a":"foo","b":"world","c":2}'),
    ('{"a":[{"b":"win"},{"c":"amp"},"hello"]}'),
    ('[{"a":"win"}]'),
    ('["win","amp"]'))
select * 
from t 
where exists (
  select *
  from jsonb_enum_values(t.x) j(x) 
  where j.x = '"win"');

Note that doublequotes around the string value.

Abelisto
  • 14,826
  • 2
  • 33
  • 41
  • If my json contains an array value, it's failing. – Deepak Kumar Padhy Apr 07 '17 at 07:14
  • @DeepakKumarPadhy Thanks for attention. Function and example updated. – Abelisto Apr 07 '17 at 08:04
  • I fell like your stored proc will work for my problem ( http://stackoverflow.com/questions/43252423/searching-for-a-particular-value-in-a-jsonb-datatype-prostgresql ) . I am not sure if this is the most optimised way, any suggestion for my problem . – Deepak Kumar Padhy Apr 07 '17 at 08:35
  • 1
    @DeepakKumarPadhy The most optimized way is to use true relational model instead of JSON columns. In few words: if you planning to search for data by content of JSON column - do not use JSON :) Probably that's why you are still have not an answer to your another question. You are using annoying but very popular [anti-pattern](https://blog.2ndquadrant.com/postgresql-anti-patterns-unnecessary-jsonhstore-dynamic-columns/) – Abelisto Apr 07 '17 at 08:59