Dismiss
Announcing Stack Overflow Documentation

We started with Q&A. Technical documentation is next, and we need your help.

Whether you're a beginner or an experienced developer, you can contribute.

Sign up and start helping → Learn more about Documentation →

I have a table with JSON array data I'd like to search.

CREATE TABLE data (id SERIAL, json JSON);

INSERT INTO data (id, json) 
  VALUES (1, '[{"name": "Value A", "value": 10}]');

INSERT INTO data (id, json) 
  VALUES (2, '[{"name": "Value B1", "value": 5}, {"name": "Value B2", "value": 15}]');

As described in this answer, i created a function, which also allows to create an index on the array data (important).

CREATE OR REPLACE FUNCTION json_val_arr(_j json, _key text)
  RETURNS text[] AS
$$
SELECT array_agg(elem->>_key)
FROM   json_array_elements(_j) AS x(elem)
$$
  LANGUAGE sql IMMUTABLE;

This works nicely if I want to find an entire value (eg. "Value B1"):

SELECT *
FROM data
WHERE '{"Value B1"}'::text[] <@ (json_val_arr(json, 'name'));

Now my questions:

  1. Is it possible to find values with a wildcard (eg. "Value*")? Something like the following (naive) approach:

    ...
    WHERE '{"Value%"}'::text[] <@ (json_val_arr(json, 'name'));
    
  2. Is it possible to find numeric values with comparison operators (eg. >= 10)? Again, a naive and obviously wrong approach:

    ...
    WHERE '{10}'::int[] >= (json_val_arr(json, 'value'));
    

    I tried to create a new function returning int[] but that did not work.

I created a SQL Fiddle to illustrate my problem.

Or would it be better to use a different approach like the following working queries:

SELECT *
FROM data,
   json_array_elements(json) jsondata
WHERE jsondata ->> 'name' LIKE 'Value%';

and

...
WHERE cast(jsondata ->> 'value' as integer) <= 10;

However, for these queries, I was not able to create any index that was actually picked up by the queries.

Also, I'd like to implement all this in Postgresql 9.4 with JSONB eventually, but I think for the above questions this should not be an issue.

Thank you very much!

share|improve this question

I know its been a while but I was just chugging on something similar (using wild cards to query json datatypes) and thought I'd share what I found.

Firstly, this was a huge point in the right direction: http://schinckel.net/2014/05/25/querying-json-in-postgres/

The take away is that your method of exploding the json element into something else (a record-set) is the way to go. It lets you query the json elements with normal postgres stuff.

In my case:

#Table:test
    ID | jsonb_column
     1 | {"name": "", "value": "reserved", "expires_in": 13732}
     2 | {"name": "poop", "value": "{\"ns\":[\"Whaaat.\"]}", "expires_in": 4554} 
     3 | {"name": "dog", "value": "{\"ns\":[\"woof.\"]}", "expires_in": 4554} 

Example Query

select * from test jsonb_to_recordset(x) where jsonb_column->>'name' like '%o%';

# => Returns
# 2 | {"name": "poop", "value": "{\"ns\":[\"Whaaat.\"]}", "expires_in": 4554}

And to answer your question about jsonb: It looks like jsonb is the better route MOST of the time. It has more methods and faster read (but slower write) times.

Sources:

Happy hunting!

share|improve this answer
    
What is the x referring to? Can't figure out how to make this query run – fgblomqvist Jun 14 at 16:37
    
Not sure what the x is either but this worked for me: SELECT COUNT(*) FROM people, jsonb_to_record(peop‌​le.data) AS x(title text) WHERE x.title LIKE '%Police%'" Assuming the people.data is a jsonb column and has a key called title. Note that it's expanding to a record not recordset. – user1032752 Aug 3 at 23:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.