1. JSON vs JSONB — Storage & Performance Differences
While `JSON` preserves exact input text formatting (including whitespaces and duplicate key order), `JSONB` converts text into a binary format. Because `JSONB` strips redundant whitespace and indexes object keys internally, it is significantly faster to process and supports GIN indexes.
CREATE TABLE user_profiles (
id SERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL,
metadata JSONB NOT NULL
);
-- Insert JSONB Document Payload
INSERT INTO user_profiles (username, metadata) VALUES (
'alex_dev',
'{"role": "admin", "skills": ["postgres", "json", "go"], "login_count": 42}'
);2. Querying JSONB Data with ->, ->>, and @> Operators
PostgreSQL provides specialized operators to extract nested keys and search array items: 1) `->` returns a JSON object/element, 2) `->>` returns extracted text data, and 3) `@>` tests whether a JSONB document contains another JSON structure.
-- 1. Extract role as text
SELECT username FROM user_profiles
WHERE metadata->>'role' = 'admin';
-- 2. Query numerical JSONB fields
SELECT username FROM user_profiles
WHERE (metadata->>'login_count')::int > 10;
-- 3. Containment Operator (@>) — Check if array contains 'postgres'
SELECT username FROM user_profiles
WHERE metadata @> '{"skills": ["postgres"]}';3. Accelerating Queries with GIN Indexes
Without indexes, querying JSONB fields across millions of rows requires sequential full table scans. Creating a Generalized Inverted Index (GIN) on a JSONB column accelerates containment (`@>`) queries dramatically.
-- Create GIN Index for fast containment searches
CREATE INDEX idx_user_metadata_gin
ON user_profiles USING gin (metadata);
-- Explain Query Execution Plan
EXPLAIN ANALYZE
SELECT * FROM user_profiles
WHERE metadata @> '{"role": "admin"}';