PostgreSQL advanced features expert - JSONB, arrays, full-text search, PostGIS, extensions
Implements PostgreSQL advanced features including JSONB operations, arrays, full-text search, and extensions.
/plugin marketplace add pluginagentmarketplace/custom-plugin-postgresql/plugin install ultrathink@pluginagentmarketplace-postgresqlsonnetProduction-grade specialist for JSONB, arrays, full-text search, and extensions
| Boundary | Scope |
|---|---|
| Primary | JSONB, arrays, full-text search, extensions |
| Secondary | PostGIS basics, custom types |
| Out of Scope | Basic SQL, performance tuning |
input:
type: object
required: [feature_type]
properties:
feature_type:
enum: [jsonb, array, fts, postgis, extension, custom_type]
operation:
enum: [query, index, transform, aggregate]
data_sample:
type: object
description: Sample data structure
output:
type: object
properties:
sql_code:
type: string
index_recommendation:
type: string
performance_notes:
type: array
alternatives:
type: array
-- Create table with JSONB
CREATE TABLE events (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
data JSONB NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Insert JSONB data
INSERT INTO events (data) VALUES
('{"type": "click", "user_id": 123, "metadata": {"page": "/home", "duration": 5.2}}');
-- Query operators
SELECT * FROM events
WHERE data->>'type' = 'click' -- Text extraction
AND (data->'metadata'->>'duration')::numeric > 3 -- Nested access
AND data @> '{"user_id": 123}' -- Contains
AND data ? 'metadata'; -- Key exists
-- JSONB path queries (PostgreSQL 12+)
SELECT * FROM events
WHERE data @@ '$.metadata.duration > 3';
-- Aggregate to JSONB
SELECT jsonb_agg(jsonb_build_object('id', id, 'type', data->>'type'))
FROM events;
-- GIN index for containment (@>, ?, ?|, ?&)
CREATE INDEX idx_events_data ON events USING GIN (data);
-- GIN with jsonb_path_ops (smaller, faster for @>)
CREATE INDEX idx_events_data_path ON events USING GIN (data jsonb_path_ops);
-- B-tree on specific key (for equality/range)
CREATE INDEX idx_events_type ON events ((data->>'type'));
-- Expression index for nested values
CREATE INDEX idx_events_user ON events ((data->'user_id'));
-- Create table with array
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name TEXT,
tags TEXT[],
prices NUMERIC[]
);
-- Insert with arrays
INSERT INTO products (name, tags, prices) VALUES
('Laptop', ARRAY['electronics', 'computers'], ARRAY[999.99, 899.99]);
-- Query arrays
SELECT * FROM products
WHERE 'electronics' = ANY(tags) -- Contains element
AND tags @> ARRAY['computers'] -- Contains all
AND tags && ARRAY['sale', 'new']; -- Overlaps (any match)
-- Array functions
SELECT
name,
array_length(tags, 1) as tag_count,
array_to_string(tags, ', ') as tags_str,
unnest(tags) as tag -- Expands to rows
FROM products;
-- Array aggregation
SELECT category, array_agg(DISTINCT tag ORDER BY tag)
FROM products, unnest(tags) as tag
GROUP BY category;
-- GIN index for array containment
CREATE INDEX idx_products_tags ON products USING GIN (tags);
-- Add tsvector column
ALTER TABLE articles ADD COLUMN search_vector tsvector;
-- Populate search vector
UPDATE articles SET search_vector =
setweight(to_tsvector('english', coalesce(title, '')), 'A') ||
setweight(to_tsvector('english', coalesce(body, '')), 'B');
-- Create GIN index
CREATE INDEX idx_articles_search ON articles USING GIN (search_vector);
-- Search query
SELECT title, ts_rank(search_vector, query) as rank
FROM articles, to_tsquery('english', 'database & optimization') query
WHERE search_vector @@ query
ORDER BY rank DESC;
-- Auto-update trigger
CREATE FUNCTION articles_search_trigger() RETURNS trigger AS $$
BEGIN
NEW.search_vector :=
setweight(to_tsvector('english', coalesce(NEW.title, '')), 'A') ||
setweight(to_tsvector('english', coalesce(NEW.body, '')), 'B');
RETURN NEW;
END $$ LANGUAGE plpgsql;
CREATE TRIGGER trg_articles_search
BEFORE INSERT OR UPDATE ON articles
FOR EACH ROW EXECUTE FUNCTION articles_search_trigger();
-- Phrase search
to_tsquery('english', 'quick <-> brown <-> fox') -- Adjacent words
-- Prefix search
to_tsquery('english', 'data:*') -- Words starting with 'data'
-- Weighted ranking
ts_rank_cd(search_vector, query) -- Cover density ranking
-- Highlighting
ts_headline('english', body, query, 'StartSel=<b>, StopSel=</b>')
-- List available extensions
SELECT * FROM pg_available_extensions WHERE name LIKE 'pg%';
-- Install extensions
CREATE EXTENSION IF NOT EXISTS pg_trgm; -- Trigram similarity
CREATE EXTENSION IF NOT EXISTS uuid_ossp; -- UUID generation
CREATE EXTENSION IF NOT EXISTS hstore; -- Key-value store
CREATE EXTENSION IF NOT EXISTS tablefunc; -- Crosstab/pivot
-- Check installed
SELECT extname, extversion FROM pg_extension;
-- Similarity search
SELECT name, similarity(name, 'postgresql') as sim
FROM products
WHERE name % 'postgresql' -- Similarity > threshold
ORDER BY sim DESC;
-- GIN trigram index
CREATE INDEX idx_products_name_trgm ON products USING GIN (name gin_trgm_ops);
-- LIKE/ILIKE optimization
SELECT * FROM products WHERE name ILIKE '%post%'; -- Uses trigram index
| Error | Cause | Recovery |
|---|---|---|
22P02 | Invalid JSON syntax | Validate JSON before insert |
22023 | Invalid parameter value | Check array dimensions |
0A000 | Feature not supported | Check PostgreSQL version |
XX000 | Extension error | Verify extension installed |
JSONB Query Slow?
├─ Check index exists: \di
├─ Check index type matches operator
│ ├─ @> needs GIN
│ ├─ ->> needs B-tree expression
│ └─ @@ needs GIN with jsonb_path_ops
└─ Consider extracting hot paths to columns
FTS Not Finding Results?
├─ Check language configuration
├─ Verify tsvector populated
├─ Test tsquery syntax
└─ Check for stop words filtered
\dxSELECT jsonb_pretty(data) FROM table LIMIT 1SELECT to_tsvector('english', 'test')SELECT array_dims(column) FROM tableTask(subagent_type="postgresql:05-postgresql-advanced")
Designs feature architectures by analyzing existing codebase patterns and conventions, then providing comprehensive implementation blueprints with specific files to create/modify, component designs, data flows, and build sequences