Lab 18: PostgreSQL JSONB & Arrays

Time: 30 minutes | Level: Foundations | DB: PostgreSQL 15

Overview

PostgreSQL-specific features: array columns, array operators, JSONB storage, JSON path queries, jsonb_set for updates, and GIN indexes for performance.


Step 1: Setup

docker run -d --name pg-lab -e POSTGRES_PASSWORD=rootpass postgres:15
sleep 10

docker exec pg-lab psql -U postgres << 'EOF'
CREATE DATABASE jsonlab;
EOF

docker exec pg-lab psql -U postgres -d jsonlab << 'EOF'
-- Table with array and JSONB columns
CREATE TABLE products (
    product_id   SERIAL PRIMARY KEY,
    name         VARCHAR(100) NOT NULL,
    tags         TEXT[],              -- array of text
    sizes        INT[],               -- array of integers
    metadata     JSONB,               -- binary JSON (indexed, fast)
    created_at   TIMESTAMP DEFAULT NOW()
);

INSERT INTO products (name, tags, sizes, metadata) VALUES
(
    'Laptop Pro 15',
    ARRAY['electronics', 'computers', 'portable'],
    ARRAY[256, 512, 1024],
    '{"brand": "TechCo", "color": "silver", "specs": {"ram": 16, "cpu": "M2"}, "ratings": [4, 5, 5, 4], "in_stock": true, "price": 1299.99}'
),
(
    'Wireless Mouse',
    ARRAY['electronics', 'peripherals', 'wireless'],
    NULL,
    '{"brand": "ClickMaster", "color": "black", "specs": {"dpi": 1600, "buttons": 6}, "ratings": [4, 3, 5], "in_stock": true, "price": 29.99}'
),
(
    'SQL Mastery Book',
    ARRAY['books', 'education', 'technology'],
    NULL,
    '{"author": "Jane Doe", "isbn": "978-0-000-00000-0", "edition": 3, "ratings": [5, 5, 4, 5], "in_stock": false, "price": 49.99}'
),
(
    'Ergonomic Chair',
    ARRAY['furniture', 'office', 'ergonomic'],
    ARRAY[1, 2, 3],
    '{"brand": "ComfortSeat", "color": "gray", "specs": {"max_weight_kg": 120, "adjustable": true}, "ratings": [4, 4, 3], "in_stock": true, "price": 399.99}'
),
(
    'USB-C Hub',
    ARRAY['electronics', 'peripherals', 'connectivity'],
    NULL,
    '{"brand": "ConnectAll", "color": "silver", "specs": {"ports": 7, "usb3": true}, "ratings": [5, 4, 5, 5], "in_stock": true, "price": 49.99}'
);
EOF

Step 2: Array Columns — Basic Operations

📸 Verified Output (tags[1]):


Step 3: Array Operators

📸 Verified Output (@> contains 'electronics'):

📸 Verified Output (&& overlap):


Step 4: JSONB Extraction — -> and ->>

📸 Verified Output:

💡 Use -> when you need the result as JSONB (for further JSON operations). Use ->> when you want a text value (for comparison or display).


Step 5: JSONB Key Existence and Querying

📸 Verified Output (in_stock = true, sorted by price):


Step 6: jsonb_set — Update JSONB Values

📸 Verified Output (after updates):


Step 7: GIN Index on JSONB

📸 Verified Output (EXPLAIN with GIN index):

💡 GIN (Generalized Inverted Index) indexes every element inside the JSONB/array. For large tables with JSONB queries using @>, ?, ?|, ?&, or array operators, GIN indexes can be 100x faster than sequential scans.


Step 8: Capstone — JSONB Analytics

📸 Verified Output (avg ratings):

Cleanup:


Summary

Feature
Syntax
Description

Array column

TEXT[], INT[]

Array of type

Array literal

ARRAY['a','b'] or '{a,b}'

Create array value

Array element

col[1]

Access 1-indexed element

Contains

col @> ARRAY['x']

Array contains value

Contained by

ARRAY['x'] <@ col

Subset of array

Overlap

col && ARRAY['x','y']

Any in common

Any

'x' = ANY(col)

Value in array

Unnest

unnest(col)

Expand to rows

JSONB get (JSONB)

col -> 'key'

Returns JSONB

JSONB get (text)

col ->> 'key'

Returns TEXT

JSONB nested

col -> 'a' -> 'b'

Chain navigation

Key exists

col ? 'key'

Boolean

JSONB contains

col @> '{"k":"v"}'

Subset match

JSONB update

jsonb_set(col, '{key}', val)

Immutable update

JSONB merge

col || '{"k":"v"}'::jsonb

Merge objects

GIN index

CREATE INDEX ON t USING GIN (col)

Indexes all keys

Next: Lab 19 — MySQL Specific Features

Last updated