The essentials

Quick reference

One focused task per row. Jump to the related section for complete, working examples.

UseSyntaxExamples
Create JSONB'{"status":"open"}'::jsonbView examples
Read JSON fieldpayload -> 'customer'View examples
Read text fieldpayload ->> 'status'View examples
Read a nested pathpayload #>> '{customer,email}'View examples
Test containmentpayload @> '{"status":"open"}'::jsonbView examples
Test a keypayload ? 'status'View examples
Match a JSON pathpayload @? '$.items[*] ? (@.price > 100)'View examples
Build an objectjsonb_build_object('id', id, 'name', name)View examples
Aggregate JSON objectsjsonb_agg(jsonb_build_object('id', id) ORDER BY id)View examples
Set a nested valuejsonb_set(payload, '{status}', '"closed"'::jsonb)View examples
Expand an arrayCROSS JOIN LATERAL jsonb_array_elements(payload -> 'items') AS itemView examples
Index JSONB operationsCREATE INDEX events_payload_gin_idx ON events USING GIN (payload);View examples

json preserves input text details; jsonb stores a decomposed binary representation optimized for processing and indexing. Use jsonb for most queryable documents, keep stable relational attributes in typed columns, and validate document shape at ingestion rather than scattering assumptions across queries.

Step by step

Detailed examples

01

Distinguish missing, JSON null, and SQL null

jsonb normalizes object representation and rejects some values that json text may accept. -> returns JSON, ->> returns text, and extraction returns SQL null when structure is absent rather than raising. JSON null is still a JSON value, so test type and key existence when the distinction matters.

Extract typed and text-shaped values
WITH docs(payload) AS (VALUES ('{"customer":{"email":"ada@example.com"},"status":null}'::jsonb))
SELECT payload -> 'status' AS json_value, payload ->> 'status' AS text_value, payload #>> '{customer,email}' AS email FROM docs;
Back to quick reference ↑
02

Use containment for structural matching

@> tests whether JSONB contains a structure and is often easier to index than extracting and casting every value. ? checks top-level keys or string array elements. SQL/JSON path supports richer predicates; lax and strict modes differ when structures do not match.

Find open documents with expensive items
SELECT event_id
FROM events
WHERE payload @> '{"status":"open"}'::jsonb
  AND payload @? '$.items[*] ? (@.price > 100)';
Back to quick reference ↑
03

Construct JSON from typed SQL values

Build functions convert SQL values according to PostgreSQL JSON rules and avoid error-prone string concatenation. Order aggregate inputs inside jsonb_agg when array order is part of the API. jsonb_set returns a new value, so an UPDATE must assign its result.

Build an ordered API payload
SELECT jsonb_build_object(
  'customer_id', customer_id,
  'orders', jsonb_agg(jsonb_build_object('id', order_id, 'total', total) ORDER BY created_at)
)
FROM orders
GROUP BY customer_id;
Back to quick reference ↑
04

Expand documents with lateral set-returning functions

jsonb_array_elements emits one JSONB row per array item and belongs in FROM for clear cardinality. Use WITH ORDINALITY when source order matters. Validate that the target is an array or normalize with CASE, because calling an array function on another JSON type raises an error.

Expand order items
SELECT o.order_id, item.value ->> 'sku' AS sku, item.ordinality
FROM orders AS o
CROSS JOIN LATERAL jsonb_array_elements(o.payload -> 'items') WITH ORDINALITY AS item(value, ordinality)
ORDER BY o.order_id, item.ordinality;
Back to quick reference ↑
05

Index stable access patterns, not every document

The default jsonb GIN operator class supports key, containment, and jsonpath operators; jsonb_path_ops is smaller and specialized for containment/jsonpath but not key-existence operators. Expression indexes can target frequently extracted scalars. Cast and validate types consistently so queries match the index expression.

General and scalar-targeted indexes
CREATE INDEX events_payload_gin_idx ON events USING GIN (payload);
CREATE INDEX events_status_idx ON events ((payload ->> 'status'));
Back to quick reference ↑

Sources and further reading

References

Authoritative documentation used to verify and expand this cheat sheet.

  1. PostgreSQL Global Development GroupPostgreSQL: JSON Typespostgresql.org
  2. PostgreSQL Global Development GroupPostgreSQL: JSON Functions and Operatorspostgresql.org
  3. PostgreSQL Global Development GroupPostgreSQL: GIN Indexespostgresql.org

Help us improve

Found a typo or missing example?

Tell us what would make this cheat sheet clearer, more complete, or more useful.

Share feedback