Parse JSON in PostgreSQL with operators (->, ->>, #>) and functions to extract, cast, and filter data stored in json/jsonb columns.
PostgreSQL’s native json
and jsonb
types let you keep semi-structured data without losing SQL power. You can index, query, and join JSON alongside relational columns, ideal for evolving ecommerce schemas.
json
preserves raw text; jsonb
stores a binary representation that supports indexing and faster lookups. For most workloads choose jsonb
.
Use ->>
for text, ->
for JSON. Example: SELECT details ->> 'status' FROM Orders;
Yes. #>
and #>>
accept path arrays. Example: details #>> '{shipping,address,city}'
returns the city as text.
jsonb_array_elements()
or json_array_elements()
turns each array element into a row—perfect for order line items.
Cast text to the target type: (details ->> 'total_amount')::numeric
. Always cast before comparing numerics or dates.
Combine operators with WHERE
. Example: WHERE details ->> 'status' = 'shipped'
.
1) Prefer jsonb
. 2) Create GIN indexes with jsonb_path_ops
when reading often. 3) Keep top-level keys stable to simplify queries. 4) Cast early in complex expressions.
Use jsonb_set()
: UPDATE Orders SET details = jsonb_set(details, '{status}', '"delivered"', false) WHERE id = 42;
Mistake 1: querying json
with GIN indexes—only jsonb
is supported.
Fix: migrate column to jsonb
.
Mistake 2: forgetting to cast text values before numeric comparison.
Fix: use ::numeric
, e.g., (details ->> 'total_amount')::numeric > 100
.
Use ->
/->>
for single keys, #>
/#>>
for paths, jsonb_array_elements()
for arrays, and always cast when comparing.
Yes, when its fourth argument is true
; otherwise it throws an error.
Yes, create a functional index like CREATE INDEX idx_status ON Orders ((details ->> 'status'));
JSON adds overhead, but jsonb
with proper indexes delivers millisecond reads for most workloads.
Yes, jsonb_set() replaces the value at the target path. Pass the current value to append instead.
-> returns JSON allowing further traversal; ->> returns text for direct comparison or casting.
Use it when you need complex path matching similar to XPath; it's slower but more expressive than basic operators.