Overview
A jsonpath expression such as $.items[*] ? (@.price > 100) navigates and filters inside a jsonb value. Switch from the arrow operators (->, ->>, #>) to jsonpath once a query must filter inside arrays or test conditions on nested objects. Use containment (@>) for plain key-value matches; it is simpler and GIN-indexable.
Rules
- Functions:
jsonb_path_exists,jsonb_path_query,jsonb_path_query_array,jsonb_path_match. The operators@?(path matches anything) and@@(predicate result) are the same checks in operator form. - Index with the operator, not the function. A GIN index serves
@?and@@, butjsonb_path_exists(...)inWHEREcannot use it. - GIN extracts only clauses of the form
accessor_chain == constant. Inequality filters such as> 100are not index-accelerated. jsonb_path_opsis smaller and faster but drops the key-exists operators and.*accessors.- PostgreSQL 17 added the SQL standard
JSON_EXISTS,JSON_QUERY,JSON_VALUE, andJSON_TABLE. Normalize data that you query relationally into columns.
SELECT id FROM orders WHERE data @? '$.items[*] ? (@.sku == "A1")';
CREATE INDEX idx_orders_data ON orders USING gin (data jsonb_path_ops);Related
- gin-index: the index behind
@?and@@. - btree-index: index extracted scalar fields instead.
- query-plan: confirm the GIN index is used.
- postgres-jsonb: JSONB modeling and queries.
- postgres: the Postgres reference.