1

I have a table

Visitor: (id, .., custom::jsonb[])

custom is an array of JSON objects of the form {field:string, value:string}. Example:

{"field": "apps_created", "value": "3"}

Say I want to find all the Visitors with 3 or more apps_created, how would I go about this? Note: every Visitor can have different fields and often there is not overlap with other visitors.

I've tried to consult the postgres documentation or other stackoverflow questions, but I have a hard time figuring out what functions/operators are used in this situation.

Any help is much appreciated

3
  • you could make life a lot easier by storing {'apps_created': '3'} ie drop the 'field' and 'value' from each dictionary so that instead of a dictionary with two elements you have a dictionary with one. In fact if you did this you might be able to chuck the whole array of dictionaries thing and have a large dictionary which would be so much easier to work with in postgresql and in your code Commented May 21, 2016 at 18:49
  • The reason for storing it that way is because I let users submit custom data fields/values and hence cannot know them at design time. AFAIK this is not possible when hardcoding the key like that Commented May 21, 2016 at 19:27
  • With my suggestion you still don't need to know what those fields are at design time. Commented May 22, 2016 at 0:46

1 Answer 1

1
select *
from visitor
where
  exists (
    select 1 
    from unnest(custom) t(x) 
    where x->>'field' = 'apps_created' and (x->>'value')::int >= 3);

Upd
However the classic way to implement such things in relational databases is (schematic):

create table entity (
  entity_id serial not null primary key,
  ...);

create table param (
  param_id serial not null primary key,
  param_name varchar not null unique,
  ...);

create table param_value (
  param_id int references param(param_id),
  entity_id int references entity(entity_id) on delete cascade,
  value varchar,
  ...
  primary key (param_id, entity_id));
Sign up to request clarification or add additional context in comments.

3 Comments

Awesome, thanks. Can you explain the t(x) syntax? I figure that it maps x to each element of the array, but a brief elaboration would be much appreciated
Also, with regards to indexing this query, is a GIN index on field and then value the way to go?
@Tarlen 1) It is standard syntax for subqueries in the from clause, where t is an alias for subquery and optional aliases for fields in brackets: ... from (select 1 as x) t or ... from (select 1) t(x). In our case unnest (custom) is equal to (select unnest(custom)); 2) I'v never used GIN indexes.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.