jsonb in Postgres 9.4+

You can use the same query as for 9.3+ below, just with jsonb_array_elements().

But you should rather use the jsonb "contains" operator @> in combination with a matching GIN index on the expression data->'objects':

CREATE INDEX reports_data_gin_idx ON reports
USING gin ((data->'objects') jsonb_path_ops);

SELECT * FROM reports WHERE data->'objects' @> '[{"src":"foo.png"}]';

Since the key objects holds a JSON array, we need to match the structure in the search term and wrap the array element into square brackets, too. Drop the array brackets when searching a plain record.

More explanation and options:

  • Index for finding an element in a JSON array

json in Postgres 9.3+

Unnest the JSON array with the function json_array_elements() in a lateral join in the FROM clause and test for its elements:

SELECT data::text, obj
FROM   reports r, json_array_elements(r.data#>'{objects}') obj
WHERE  obj->>'src' = 'foo.png';

db<>fiddle here
Old sqlfiddle

Or, equivalent for just a single level of nesting:

SELECT *
FROM   reports r, json_array_elements(r.data->'objects') obj
WHERE  obj->>'src' = 'foo.png';

->>, -> and #> operators are explained in the manual.

Both queries use an implicit JOIN LATERAL.

Closely related:

  • Query for element of array in JSON column
Answer from Erwin Brandstetter on Stack Overflow
Top answer
1 of 2
367

jsonb in Postgres 9.4+

You can use the same query as for 9.3+ below, just with jsonb_array_elements().

But you should rather use the jsonb "contains" operator @> in combination with a matching GIN index on the expression data->'objects':

CREATE INDEX reports_data_gin_idx ON reports
USING gin ((data->'objects') jsonb_path_ops);

SELECT * FROM reports WHERE data->'objects' @> '[{"src":"foo.png"}]';

Since the key objects holds a JSON array, we need to match the structure in the search term and wrap the array element into square brackets, too. Drop the array brackets when searching a plain record.

More explanation and options:

  • Index for finding an element in a JSON array

json in Postgres 9.3+

Unnest the JSON array with the function json_array_elements() in a lateral join in the FROM clause and test for its elements:

SELECT data::text, obj
FROM   reports r, json_array_elements(r.data#>'{objects}') obj
WHERE  obj->>'src' = 'foo.png';

db<>fiddle here
Old sqlfiddle

Or, equivalent for just a single level of nesting:

SELECT *
FROM   reports r, json_array_elements(r.data->'objects') obj
WHERE  obj->>'src' = 'foo.png';

->>, -> and #> operators are explained in the manual.

Both queries use an implicit JOIN LATERAL.

Closely related:

  • Query for element of array in JSON column
2 of 2
55

Create a table with column as type json

CREATE TABLE friends ( id serial primary key, data jsonb);

Now let's insert json data

INSERT INTO friends(data) VALUES ('{"name": "Arya", "work": ["Improvements", "Office"], "available": true}');
INSERT INTO friends(data) VALUES ('{"name": "Tim Cook", "work": ["Cook", "ceo", "Play"], "uses": ["baseball", "laptop"], "available": false}');

Now let's make some queries to fetch data

select data->'name' from friends;
select data->'name' as name, data->'work' as work from friends;

You might have noticed that the results comes as list

    name    |            work            
------------+----------------------------
 "Arya"     | ["Improvements", "Office"]
 "Tim Cook" | ["Cook", "ceo", "Play"]
(2 rows)

Now to retrieve only the values just use ->>

select data->>'name' as name, data->'work'->>0 as work from friends;
select data->>'name' as name, data->'work'->>0 as work from friends where data->>'name'='Arya';
🌐
Hashrocket
hashrocket.com › blog › posts › querying-for-json-arrays-in-postgres
Querying for JSON Arrays in Postgres | Hashrocket
June 23, 2023 - In this post we covered the fact that if there is an array in your JSON object, you simply use the Stabby operator to dig into the array, by its index. We saw that we are able to grab from the end of the array using a negative index.
Discussions

Postgresql query array of objects in JSONB field - Stack Overflow
I have a list of values for id and want to select any row that contains an object with any of the values from that list, within the array in the jsonb field. Is that possible? Is there a GIN index I can make that will speed this up? ... 1. If you have a small (and fixed) number of ids to query, you ... More on stackoverflow.com
🌐 stackoverflow.com
How to get particular object from jsonb array in PostgreSQL? - Database Administrators Stack Exchange
I'm not able to get the particular field count from an array of json objects in PostgreSQL 9.4. ... It would be much more efficient to store your values in a normalized schema. That said, you can also make it work with your current setup. ... "user" is a reserved word and would require double quoting to be used as column name. Don't do that. I use usr instead. The query ... More on dba.stackexchange.com
🌐 dba.stackexchange.com
January 29, 2016
Working with a JSONB Array of Objects in PostgreSQL
It's a good thing the article uses an example of a list of purchases made by a customer. That's just the kind of tricky use case for which traditional, simple, universally understood and highly optimised relational approaches totally suck... right? More on reddit.com
🌐 r/programming
18
43
April 10, 2023
How to query table using json array in where clause?
What does the JSON column in your table contain? It's unclear to me what exactly you are trying to achieve. Assuming your (unknown) column contains an JSON array: do you want the rows that contain at least one of those JSON objects? Or those rows that contain all of the objects in your WHERE clause? More on reddit.com
🌐 r/PostgreSQL
12
4
March 30, 2021
People also ask

How do you query an array in Jsonb?
Use jsonb_array_elements() in PostgreSQL to extract elements from a JSONB array.
🌐
hevodata.com
hevodata.com › home › learn › database management system
How to Query JSONB Array of Objects in PostgreSQL
How to parse array of JSON objects?
In most programming languages, use built-in JSON parsing libraries.
🌐
hevodata.com
hevodata.com › home › learn › database management system
How to Query JSONB Array of Objects in PostgreSQL
How to fetch array of objects in JSON?
Use functions like json_extract() or json_path_query() to extract array of objects, based on the database. For instance, in SQL Server, you can use json_value().
🌐
hevodata.com
hevodata.com › home › learn › database management system
How to Query JSONB Array of Objects in PostgreSQL
Top answer
1 of 3
30

you have to unnest the array of json-objects first using the function (json_array_elements or jsonb_array_elements if you have jsonb data type), then you can access the values by specifying the key.

WITH json_test (col) AS (
  values (json '[{"name":"Mickey Mouse","age":10},{"name":"Donald Duck","age":5}]')
)
SELECT
  y.x->'name' "name"
FROM json_test jt, 
LATERAL (SELECT json_array_elements(jt.col) x) y

-- outputs:
name
--------------
"Mickey Mouse"
"Donald Duck"

To get a count of unique names, its a similar query to the above, except the count distinct aggregate function is applied to y.x->>name

WITH json_test (col) AS (
  values (json '[{"name":"Mickey Mouse","age":10},{"name":"Donald Duck","age":5}]')
)
SELECT
  COUNT( DISTINCT y.x->>'name') distinct_names
FROM json_test jt, 
LATERAL (SELECT json_array_elements(jt.col) x) y

It is necessary to use ->> instead of -> as the former (->>) casts the extracted value as text, which supports equality comparison (needed for distinct count), whereas the latter (->) extracts the value as json, which does not support equality comparison.

Alternatively, convert the json as jsonb and use jsonb_array_elements. JSONB supports the equality comparison, thus it is possible to use COUNT DISTINCT along with extraction via ->, i.e.

COUNT(DISTINCT (y.x::jsonb)->'name')

updated answer for postgresql versions 12+

It is now possible to extract / unnest specific keys from a list of objects using jsonb path queries, so long as the field queried is jsonb and not json.

example:

WITH json_test (col) AS (
  values (jsonb '[{"name":"Mickey Mouse","age":10},{"name":"Donald Duck","age":5}]')
)
SELECT jsonb_path_query(col, '$[*].name') "name"
FROM json_test
-- replaces this original snippet:
-- SELECT
--   y.x->'name' "name"
-- FROM json_test jt, 
-- LATERAL (SELECT json_array_elements(jt.col) x) y
2 of 3
22

Do like this:

SELECT * FROM json_test WHERE (column_name @> '[{"name": "Mickey Mouse"}]');
🌐
Hevo
hevodata.com › home › learn › database management system
How to Query JSONB Array of Objects in PostgreSQL
March 24, 2026 - Use jsonb_array_elements() in PostgreSQL to extract elements from a JSONB array. Use functions like json_extract() or json_path_query() to extract array of objects, based on the database.
🌐
DEV Community
dev.to › franckpachot › query-and-index-json-array-fields-in-postgresql-and-mongodb-3md
Querying embedded arrays in JSON (PostgreSQL JSONB and MongoDB documents) - DEV Community
May 2, 2025 - When working with document-based data structures, the fields at the root can be indexed using simple expression indexes. However, when an array is present in the path, representing a One-to-Many relationship, PostgreSQL requires a GIN index and the use of JSON path operators for indexing, more efficient than SQL/JSON queries.
🌐
CommandPrompt Inc.
commandprompt.com › education › how-to-query-jsonb-array-of-objects-in-postgresql
How to Query JSONB Array of Objects in PostgreSQL — CommandPrompt Inc.
August 14, 2023 - To query the JSONB array of objects in PostgreSQL, simply create a table with a JSONB column and insert data into the table. Use different operators to query the JSONB data and retrieve the desired information from the table.
Find elsewhere
🌐
PostgreSQL
postgresql.org › docs › 9.4 › functions-json.html
PostgreSQL: Documentation: 9.4: JSON Functions and Operators
February 13, 2020 - Note: While the examples for the functions json_populate_record, json_populate_recordset, json_to_record and json_to_recordset use constants, the typical use would be to reference a table in the FROM clause and use one of its json or jsonb columns as an argument to the function. Extracted key values can then be referenced in other parts of the query, like WHERE clauses and target lists.
Top answer
1 of 2
88

There is no single operation, which can help you, but you have a few options:

1. If you have a small (and fixed) number of ids to query, you can use multiple containment operators @> combined with or; f.ex.:

where data @> '[{"id": "1884595530"}]' or data @> '[{"id": "791712670"}]'

A simple gin index can help you on your data column here.

2. If you have variable number of ids (or you have a lot of them), you can use json[b]_array_elements() to extract each element of the array, build up an id list and then query it with the any-containment operator ?|:

select *
from   jsonbtest
where  to_json(array(select jsonb_array_elements(data) ->> 'id'))::jsonb ?|
         array['1884595530', '791712670'];

Unfortunately, you cannot index an expression, which has a sub-query in it. If you want to index it, you need to create a function for it:

create function idlist_jsonb(jsonbtest)
  returns jsonb
  language sql
  strict
  immutable
as $func$
  select to_json(array(select jsonb_array_elements($1.data) ->> 'id'))::jsonb
$func$;

create index on jsonbtest using gin (idlist_jsonb(jsonbtest));

After this, you can query ids like this:

select *, jsonbtest.idlist_jsonb
from   jsonbtest
where  jsonbtest.idlist_jsonb ?| array['193623800', '895207852'];

Note: I used dot notation / computed field here, but you don't have to.

3. But at this point, you don't have to stick with json[b]: you have a simple text array, which is supported by PostgreSQL too.

create function idlist_array(jsonbtest)
  returns text[]
  language sql
  strict
  immutable
as $func$
  select array(select jsonb_array_elements($1.data) ->> 'id')
$func$;

create index on jsonbtest using gin (idlist_array(jsonbtest));

And query this computed field with the overlap array operator &&:

select *, jsonbtest.idlist_array
from   jsonbtest
where  jsonbtest.idlist_array && array['193623800', '895207852'];

Note: From my internal testing, this latter solution is calculated with a higher cost than the jsonb variant, but in fact it is faster than that, a little. If performance really matters to you, you should test both.

2 of 2
11

I find workaround:
where data::text similar to '%("id": "145119603"|"id": "1884595530")%'

🌐
TigerData
tigerdata.com › learn › how-to-query-jsonb-in-postgresql
How to Query JSONB in PostgreSQL | Tiger Data
February 17, 2025 - PostgreSQL includes two native operators: arrow operator (->) and arrow-text operator (->>) to query JSONB documents. The arrow operator -> returns a JSONB object field by key or array index and is suitable for navigating nested structures.
🌐
Dustinmartin
dustinmartin.net › query-array-of-objects-in-postgres
Query Array of Objects in Postgres - Dustin Martin
The trick is to use jsonb_array_elements to expand the array into a row for every object. Then each object can be queried individually by using the ->> operator extract a key and use it in a where clause.
🌐
GitConnected
levelup.gitconnected.com › working-with-a-jsonb-array-of-objects-in-postgresql-d2b7e7f4db87
Working with a JSONB Array of Objects in PostgreSQL | by gravity well (Rob Tomlin) | Level Up Coding
September 9, 2023 - In my last article, we focused on turning a PostgreSQL jsonb column, that contained an Array of Objects, into a recordset, so that it could be queried in a relational manner.
🌐
PostgreSQL
postgresql.org › docs › current › functions-json.html
PostgreSQL: Documentation: 18: 9.16. JSON Functions and Operators
August 13, 2026 - To provide native support for JSON data types within the SQL environment, PostgreSQL implements the SQL/JSON data model. This model comprises sequences of items. Each item can hold SQL scalar values, with an additional SQL/JSON null value, and ...
🌐
PostgreSQL
postgresql.org › docs › 9.5 › functions-json.html
PostgreSQL: Documentation: 9.5: JSON Functions and Operators
February 11, 2021 - It does not operate recursively; only the top-level array or object structure is merged. Table 9-42 shows the functions that are available for creating json and jsonb values. (There are no equivalent functions for jsonb, of the row_to_json and array_to_json functions.
🌐
Devhints
devhints.io › databases › postgresql json cheatsheet
PostgreSQL JSON cheatsheet
> returns JSON, >> returns text. SELECT * FROM users WHERE data->tags ? 'admin'; SELECT data->tags ? 'admin' AS is_admin FROM users; When ?/?|/?& works on objects, it checks keys; when it works on arrays, it checks for elements. UPDATE users SET tags = tags || array['admin']; Only available in PostgreSQL 9.5+. UPDATE users SET data = jsonb_set(data, '{name}', '"John"'); Only available in PostgreSQL 9.5+. jsonb_set(data, '{path}', value) jsonb_strip_nulls(data) to_json("Hello"::text) array_to_json('{1,2}'::int[]) SELECT * from json_each('{"a":1, "b":2}') SELECT * from json_each_text('{"a":1, "b":2}') -- key | value ·
🌐
Medium
nrogap.medium.com › query-array-json-in-postgresql-2b06356628a
Query Array JSON in PostgreSQL - Pagorn Phusaisakul
June 14, 2022 - SELECT * FROM notes WHERE details::JSONB @> '[{ "phone_number": null }]';-- Result --id | details ---+-------------------------- 3 | [{"phone_number": null}]
🌐
Medium
medium.com › @AaronSchlegel › query-json-data-with-postgresql-73512884212c
Query JSON Data with PostgreSQL. Support for working with JSON in… | by Aaron Schlegel | Medium
July 30, 2021 - For example, suppose it is likely that querying for particular items contained in each JSON object’s “tags” array will be expected. In that case, we could use an expression index to create a GIN index similar to the following: CREATE INDEX pet_index_tags on pets USING GIN ((pet_data -> ‘tags’)); We introduced and explored several more common operators for querying and extracting JSON data in PostgreSQL tables in this post. A detailed table of all the available operators for both json and jsonb is also available here.
🌐
Foxy Panda ~
foxypanda.me › returning-an-array-of-json-objects-in-postgresql
Returning an array of JSON objects in PostgreSQL
January 1, 2024 - For my internship with Microsoft and UCL Institute of Child Health I had to work with PostgreSQL. My back-end was running on Node.js, so naturally I was interested in getting JSON formatted data out of Postgres whenever possible. Alternative solution was to handle all the logic using JavaScript and
Top answer
1 of 2
29

It would be much more efficient to store your values in a normalized schema. That said, you can also make it work with your current setup.

Assumptions

Assuming this table definition:

CREATE TABLE tbl (tbl_id int, usr jsonb);

"user" is a reserved word and would require double quoting to be used as column name. Don't do that. I use usr instead.

Query

The query is not as trivial as the (now deleted) comments made it seem:

SELECT t.tbl_id, obj.val->>'count' AS count
FROM   tbl t
JOIN   LATERAL jsonb_array_elements(t.usr) obj(val) ON obj.val->>'_id' = '1'
WHERE  t.usr @> '[{"_id":"1"}]';

There are 3 basic steps:

1. Identify qualifying rows cheaply

WHERE t.usr @> '[{"_id":"1"}]' identifies rows with matching object in the JSON array. The expression can use a generic GIN index on the jsonb column, or one with the more specialized operator class jsonb_path_ops:

CREATE INDEX tbl_usr_gin_idx ON tbl USING gin (usr jsonb_path_ops);

The added WHERE clause is logically redundant, but it is required to use the index. The expression in the join clause enforces the same condition but only after unnesting the array in every row qualifying so far. With index support, Postgres only processes rows that contain a qualifying object to begin with. Does not matter much with small tables, makes a huge difference with big tables and only few qualifying rows.

Related:

  • PostgreSQL operator uses index but underlying function does not
  • Index for finding an element in a JSON array

2. Identify matching object(s) in the array

Unnest with jsonb_array_elements(). (unnest() is only good for Postgres array types.) Since we are only interested in actually matching objects, filter in the join condition right away.

Related:

  • How to turn JSON array into Postgres array?

3. Extract value for nested key 'count'

After qualifying objects have been extracted, simply: obj.val->>'count'.

2 of 2
2

In postgres 12 or later, you can use jsonb_path_query.

WITH cte (
    js
) AS (
    VALUES ('[{ "_id" : "1", "count" : "4" }, { "_id" : "3", "count": "4"}]'))
SELECT
    jsonb_path_query(js::jsonb, '$[*] ? (@._id == "1")') ->> 'count'
FROM
    cte;

🌐
Data and Open Source
ftisiot.net › postgresqljson › how-to-parse-json-arrays-in-postgresql
How to parse JSON arrays in PostgreSQL? | Data and Open Source
January 9, 2023 - PostgreSQL® offers two types of ... arrays from a JSON document: the json_array_elements (jsonb_array_elements for JSONB columns) function to extract the array elements as JSON objects...