JSONB Recordset Expansion

Problem / Context

Your service receives arrays of JSON objects (users, products, events) and you need to insert or upsert them as rows. You want a single set-based query instead of looping, with validation and safe updates when records already exist.

Convert JSON array of objects into relational rows.

Core Concept

Implementation (Step by Step SQL)

jsonb_to_recordset

WITH incoming AS (
  SELECT * FROM jsonb_to_recordset($1::jsonb)
    AS t(id uuid, name text, attrs jsonb, updated_at timestamptz)
)
INSERT INTO users AS u (id, name, attrs, updated_at)
SELECT id, name, attrs, updated_at
FROM incoming
ON CONFLICT (id) DO UPDATE
SET name = EXCLUDED.name,
    attrs = EXCLUDED.attrs,
    updated_at = EXCLUDED.updated_at
WHERE u.updated_at < EXCLUDED.updated_at;

Dynamic Columns

Define only needed columns; extra keys ignored unless captured as jsonb.

Validation

Pre-validate JSON schema in app or use CHECK constraints on computed columns.

Performance

When to Use vs UNNEST Arrays

Situation Prefer
Many optional fields Recordset
Uniform typed columns UNNEST
Sparse wide objects Recordset

For CRUD path updates see 13-jsonb-crud.md.

Variations and Trade‑Offs

Pitfalls

Recap (Short Summary)

Turn arrays of JSON objects into rows with jsonb_to_recordset and upsert them with one statement. Use freshness guards and consider staging for complex validation.

Optional Exercises

Summary (Cheat Sheet)

Guideline: Use recordset for moderately wide semi-structured batches; switch to staging when validation complexity rises.

References