1

I have a column with type jsonb holding a list of IDs as plain JSON array in my PostgreSQL 9.6.6 database and I want to search this field based on any ID in the list. How to query write this query?

'[1,8,3,4,56,6]'

For example, my table is:

CREATE TABLE mytable (
    id bigint NOT NULL,
    numbers jsonb
);

And it has some values:

 id  |  numbers
-----+-------
 1   | "[1,8,3,4,56,6]"
 2   | "[1,2,7,4,24,5]"

I want something like this:

SELECT * 
FROM mytable
WHERE
id = 1
AND
numbers::json->>VALUE(56)
;

Expected result (only if the JSON array has 56 as element):

 id  |  numbers
-----+-------
 1   | "[1,8,3,4,56,6]"

Step-2 problem :

The result of this command is TRUE :

SELECT '[1,8,3,4,56,6]'::jsonb @> '56';

but already when I use

SELECT * 
FROM   mytable
numbers::jsonb @> '[56]';

or

SELECT * 
FROM   mytable
numbers::jsonb @> '56';

or

SELECT * 
FROM   mytable
numbers::jsonb @> '[56]'::jsonb;

The result is nothing :

 id  |  numbers
-----+-------
(0 rows)

Instead of be this :

 id  |  numbers
-----+-------
 1   | "[1,8,3,4,56,6]"

I find why I get (0 rows) ! :))

because I insert jsonb value to mytable with double quotation , in fact this is correct value format (without double quotation ):

 id  |  numbers
-----+-------
 1   | [1,8,3,4,56,6]
 2   | [1,2,7,4,24,5] 

now when run this command:

SELECT * 
FROM   mytable
numbers @> '56';

The result is :

 id  |  numbers
-----+-------
 1   | [1,8,3,4,56,6]
Mojtaba Arvin
  • 679
  • 1
  • 10
  • 21

1 Answers1

2

Use the jsonb "contains" operator @>:

SELECT * 
FROM   mytable
WHERE  id = 1
AND    numbers @> '[56]';

Or

...
AND    numbers @> '56';

Works with our without enclosing array brackets in this case.

dbfiddle here

This can be supported with various kinds of indexes for great read performance if your table is big.

Detailed explanation / instructions:


Hint (addressing your comment): when testing with string literals, be sure to add an explicit cast:

SELECT '[1,8,3,4,56,6]'::jsonb @> '56';

If you don't, Postgres does not know which data types to assume. There are multiple options:

SELECT '[1,8,3,4,56,6]' @> '56';

ERROR:  operator is not unique: unknown @> unknown

Related:

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
  • I get this error : ERROR : operator is not unique: unknown @> unknown HINT: Could not choose a best candidate operator ... – Mojtaba Arvin Jan 07 '18 at 13:32
  • @MojtabaArvin: Doesn't make sense. I tested in Postgres 9.6, it's working. What's your version of Postgres? (Should be in the question to begin with.) – Erwin Brandstetter Jan 07 '18 at 13:36
  • You would't get `unknown` in the error msg if the column is type `jsonb`. You probably tested with untyped string literals, which is misleading. – Erwin Brandstetter Jan 07 '18 at 13:39
  • How do I search for multiple values like AND numbers @> '[56,4]'; How do I search for any values from AND numbers @> '[56]' OR '[4]'; – ajitpawarink May 31 '23 at 11:58
  • 1
    @ajitpawarink: One way: `numbers @> ANY ('{56, 4}'::jsonb[])`, which is short for `(numbers @> '56'::jsonb OR numbers @> '7'::jsonb);` Or `numbers @? '$[*] ? (@ == 56 || @ == 7)'`. Unfortunately, `numbers ?| '{56, 7}'::text[]` only works for *string* elements, not for *numeric* elements. Start a separate question if you need more details. – Erwin Brandstetter May 31 '23 at 21:20