In Postgres 9.6, why is the GIN index not used for a JSONB column with text/int array?
If you want an index to be used for searching in an array, you need to first store the values as a proper array, not as a string with comma separated values that are enclosed with curly braces, e.g: {"types": [1,2], "name": "item_name1"}

Then you need to access the value as JSONB, not as text. So you need to use -&gt; not -&gt;&gt;. 

SELECT * 
FROM items
WHERE metadata -&gt; 'types'  @&gt; '[52,53]'::jsonb


And finally you need to index the types array to make that work, not the complete content of the metadata column:

create index idx_metadata_types on items using gin  ((metadata -&gt; 'types'));




To test the index usage, you need a substantially larger table than the one you have with just 38 rows. 

Using this query:

explain (analyze, buffers)
SELECT * 
FROM items
WHERE metadata -&gt; 'types' @&gt; '[52,53]'::jsonb


On a table with 100000 rows I then get the following plan (using Postgres 11 on my Windows 10 laptop):

Bitmap Heap Scan on items  (cost=5.38..103.08 rows=100 width=78) (actual time=0.315..0.422 rows=54 loops=1)
  Recheck Cond: ((metadata -&gt; 'types'::text) @&gt; '[52, 53]'::jsonb)
  Heap Blocks: exact=51
  Buffers: shared hit=57
  -&gt;  Bitmap Index Scan on idx_metadata_types  (cost=0.00..5.35 rows=100 width=0) (actual time=0.298..0.298 rows=54 loops=1)
        Index Cond: ((metadata -&gt; 'types'::text) @&gt; '[52, 53]'::jsonb)
        Buffers: shared hit=6
Planning Time: 0.081 ms
Execution Time: 0.453 ms