JSONB Deep Dive: Querying, Indexing, and Optimizing PostgreSQL Documents
JSONB lets you store variable, evolving payloads inside a normal PostgreSQL table without losing transactions, joins, or constraints on everything else. The difference between "JSONB is slow" and "JSONB is fine at scale" almost always comes down to three things: which operator you query with, which index backs it, and whether the planner is actually using that index. Here's the reference.
Query Operators That Matter
-- payload = '{"user": {"name": "Ada", "roles": ["admin", "editor"]}}'
payload -> 'user' ->> 'name' -- 'Ada' (text extraction)
payload #> '{user,roles}' -- ["admin","editor"] (jsonb path extraction)
-- Containment — the operator your indexes should target
payload @> '{"user": {"roles": ["editor"]}}' -- true/false, recursive, order-independent
-- Key existence
payload ? 'discount_code' -- top-level key exists
payload ?| array['error','warning'] -- any of these keys exist
Per the official JSON Functions and Operators docs, @> checks structural containment recursively — this is the operator to default to for "does this document match" queries, because it's also the one GIN indexes accelerate directly.
For conditions inside nested arrays, use jsonpath instead of pulling data out and filtering in application code:





