JSON and JSONB Columns

Create tables with JSON and JSONB columns for flexible metadata and semi-structured data storage

All recipes· core-foundations· 12 minutesbeginner

JSON and JSONB Columns

Objective

Create tables with JSON and JSONB columns for storing flexible, semi-structured data. JSON columns are ideal for metadata, configurations, and data that varies between records.

Step 1: Create Table with JSON Column

Create a table using JSON for flexible metadata storage.

CREATE TABLE products (
    id INTEGER PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    base_price DECIMAL(10, 2) NOT NULL,
    metadata JSON,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Step 2: Insert Records with JSON Data

Insert records with varied JSON structures.

INSERT INTO products (id, name, base_price, metadata) VALUES
(1, 'Laptop Pro', 1299.99,
    '{"brand": "TechCo", "specs": {"cpu": "Intel i7", "ram": "16GB", "storage": "512GB SSD"}, "colors": ["silver", "black"]}'),
(2, 'Wireless Mouse', 49.99,
    '{"brand": "ClickMaster", "specs": {"dpi": 1600, "buttons": 6, "wireless": true}, "colors": ["black", "white", "blue"]}'),
(3, 'USB Hub', 29.99,
    '{"brand": "ConnectAll", "specs": {"ports": 7, "usb_version": "3.0", "powered": true}}');

Step 3: Create Table with JSONB Column

JSONB is binary JSON format, optimized for querying.

CREATE TABLE user_preferences (
    id INTEGER PRIMARY KEY,
    user_id INTEGER NOT NULL,
    preferences JSONB,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO user_preferences (id, user_id, preferences) VALUES
(1, 101, '{"theme": "dark", "language": "en", "notifications": {"email": true, "push": false, "sms": false}}'),
(2, 102, '{"theme": "light", "language": "es", "notifications": {"email": true, "push": true, "sms": true}}'),
(3, 103, '{"theme": "auto", "language": "fr", "notifications": {"email": false, "push": true, "sms": false}}');

Step 4: Store Complex Nested JSON

Create a table for storing event data with complex JSON structures.

CREATE TABLE events (
    id INTEGER PRIMARY KEY,
    event_type VARCHAR(50) NOT NULL,
    event_data JSON NOT NULL,
    occurred_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO events (id, event_type, event_data) VALUES
(1, 'user_signup',
    '{"user": {"id": 1001, "email": "new@example.com"}, "source": "web", "campaign": "summer2024", "metadata": {"browser": "Chrome", "os": "Windows"}}'),
(2, 'purchase',
    '{"order_id": 5001, "items": [{"sku": "ABC123", "qty": 2, "price": 29.99}, {"sku": "XYZ789", "qty": 1, "price": 49.99}], "total": 109.97}'),
(3, 'page_view',
    '{"page": "/products/laptop", "referrer": "google.com", "session_id": "sess_abc123", "duration_seconds": 45}');

Step 5: Query JSON Data

Query and filter records based on JSON content.

-- Select all products with their metadata
SELECT id, name, base_price, metadata
FROM products;

-- Select events by type
SELECT event_type, event_data, occurred_at
FROM events
WHERE event_type = 'purchase';

Step 6: Configuration Storage with JSON

Use JSON for application configuration storage.

CREATE TABLE app_configurations (
    id INTEGER PRIMARY KEY,
    config_name VARCHAR(100) NOT NULL UNIQUE,
    config_data JSONB NOT NULL,
    is_active BOOLEAN DEFAULT TRUE,
    version INTEGER DEFAULT 1,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO app_configurations (id, config_name, config_data) VALUES
(1, 'email_settings',
    '{"smtp_host": "smtp.example.com", "smtp_port": 587, "use_tls": true, "from_address": "noreply@example.com", "templates": {"welcome": "tmpl_001", "reset": "tmpl_002"}}'),
(2, 'feature_flags',
    '{"new_dashboard": true, "beta_features": false, "dark_mode": true, "experimental_api": false}'),
(3, 'rate_limits',
    '{"api": {"requests_per_minute": 100, "burst": 20}, "uploads": {"max_size_mb": 50, "allowed_types": ["jpg", "png", "pdf"]}}');

SELECT config_name, config_data, version
FROM app_configurations
WHERE is_active = TRUE;

Step 7: Audit Log with JSON

Create an audit log table storing changes as JSON.

CREATE TABLE audit_log (
    id INTEGER PRIMARY KEY,
    table_name VARCHAR(100) NOT NULL,
    record_id INTEGER NOT NULL,
    action VARCHAR(20) NOT NULL,
    old_values JSON,
    new_values JSON,
    changed_by VARCHAR(100),
    changed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO audit_log (id, table_name, record_id, action, old_values, new_values, changed_by) VALUES
(1, 'products', 1, 'UPDATE',
    '{"base_price": 1199.99}',
    '{"base_price": 1299.99}',
    'admin@example.com'),
(2, 'users', 101, 'UPDATE',
    '{"status": "pending", "verified": false}',
    '{"status": "active", "verified": true}',
    'system'),
(3, 'products', 4, 'INSERT',
    NULL,
    '{"name": "New Product", "base_price": 79.99}',
    'admin@example.com');

SELECT table_name, record_id, action, old_values, new_values, changed_at
FROM audit_log
ORDER BY changed_at DESC;

Cleanup (Optional)

DROP TABLE IF EXISTS products;
DROP TABLE IF EXISTS user_preferences;
DROP TABLE IF EXISTS events;
DROP TABLE IF EXISTS app_configurations;
DROP TABLE IF EXISTS audit_log;

Expected Outcomes

  • JSON columns store varied structures
  • JSONB optimized for binary storage
  • Complex nested objects supported
  • Flexible schema per record
  • Ideal for metadata and configurations

JSON vs JSONB

Feature JSON JSONB
Storage Text Binary
Parsing On read On write
Duplicates Preserved Last wins
Key order Preserved Not preserved
Best for Logging Querying

Key Concepts Learned

  • JSON column type for flexible data
  • JSONB for optimized binary storage
  • Storing nested objects and arrays
  • Configuration and metadata patterns
  • Audit logging with JSON

Tags

sqlbeginnerjsonjsonbmetadatasemi-structured

Run this on your own machine

Install SynapCores Community Edition free, paste the SQL or Cypher above into the bundled web UI, and watch it run.

Download Free CE