30

Recently upgraded to using PostgreSQL 9.3.1 to leverage the JSONfunctionalities. In my table I have a json type column that has a structure like this:

{
   "id": "123",
   "name": "foo",
   "emails":[
      {
        "id": "123",
        "address": "somethinghere"
      },
      {
        "id": "456",
        "address": "soemthing"
      }
   ]
} 

This is just dummy data for the purpose of the question.

Is it possible to query for a specific item in the emails array based on the id?
Pretty much: "return email where id=123)"?

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
Joe
  • 363
  • 2
  • 4
  • 6

4 Answers4

59

For Postgres 9.4+ see adamc's later answer. Or:

Original answer for Postgres 9.3

Yes, that's possible:

SELECT *
FROM   tbl t, json_array_elements(t.json_col->'emails') AS elem
WHERE  elem->>'id' = 123;

tbl being your table name, json_col the name of the JSON column.

See also:

About the implicit CROSS JOIN LATERAL:

Index to support this kind of query:

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
  • This is the best answer I have seen for this type of question so far. – w0rp Jul 13 '16 at 10:20
  • @ErwinBrandstetter Sorry for off-top, but could you please help with this issue: https://stackoverflow.com/q/49532773 (Thanks in advance!) – Cepr0 Mar 28 '18 at 15:18
9

With a JSONB column in Postgres 9.4+ you can use the contains operator @> to query for an element in an array:

SELECT * FROM jsontest WHERE data @> '{ "emails": [{ "id": "123" }] }';

See Query for array elements inside JSON type for more details.

Here is a working example:

CREATE TABLE jsontest(data JSONB NOT NULL);
INSERT INTO jsontest VALUES (
  '{
     "name": "foo",
     "id": "123",
     "emails": 
     [
       {
         "address": "somethinghere",
         "id": "123"
       },
       {
         "address": "soemthing",
         "id": "456"
       }
     ]
  }'
);
SELECT * FROM jsontest WHERE data @> '{ "emails": [{ "id": "123" }] }';

data
----
{"id": "123", "name": "foo", "emails": [{"id": "123", "address": "somethinghere"}, {"id": "456", "address": "soemthing"}]}

(1 row)

Community
  • 1
  • 1
adamc
  • 1,315
  • 19
  • 16
3

Came across this post and found that you can directly query on table like this:

SELECT *
FROM   table_name, json_array_elements(json_column) AS data
WHERE  data->>'id' = 123;

Omitting this part:

json_array_elements(t.json_col->'emails')
Deepak Mahakale
  • 22,834
  • 10
  • 68
  • 88
  • this is super super useful I have been struggling with CTE to try and make it work, and this just solves my need beautifully. Thanks! – Mercutionario Mar 24 '17 at 17:01
-1

You can do it as simple as :

SELECT * FROM table WHERE emails->>'id' = '123';

it seems you store the id as string, if it was an integer you can do it like this :

SELECT *  from table WHERE cast(emails->>'id' as integer ) = 123  ;

or you can get all the rows with id > 10

SELECT *  from table WHERE cast(emails->>'id' as integer ) > 10  ;
Yunis Hawwash
  • 98
  • 2
  • 13