$ lexprog.com

// notes from an old coder -- php, databases, and the occasional rant

[March 06, 2026] PostgreSQL

PostgreSQL Arrays in Laravel

PostgreSQL Arrays in Laravel: Tips & Tricks

────────────────────────────────────────────────────────

PostgreSQL Arrays in Laravel: Tips & Tricks

Tip: Native Array Columns

$table->string('tags')->array();

PostgreSQL stores arrays natively. No junction table needed for simple lists.

Gotcha: Laravel's Array Cast

protected $casts = ['tags' => 'array'];

Laravel serializes to JSON by default. For PostgreSQL native arrays, use raw queries or a custom cast.

Tip: Query Array Contains

Post::whereRaw("'laravel' = ANY(tags)")->get();

Finds posts where 'laravel' is in the tags array.

Gotcha: Array Indexing

CREATE INDEX idx_posts_tags ON posts USING GIN (tags);

GIN index makes array containment queries fast.

Tip: Unnest for Aggregation

SELECT unnest(tags) as tag, count(*) FROM posts GROUP BY tag;

Gets tag frequency across all posts.

Gotcha: Array vs JSONB for Lists

Arrays are better for simple lists of the same type. JSONB is better for complex nested data.

Tip: Array Append

UPDATE posts SET tags = array_append(tags, 'new-tag') WHERE id = 1;

Adds an element without loading the whole array.

Gotcha: Empty Arrays

Post::whereRaw('tags = ARRAY[]::varchar[]')->get();

Find posts with no tags. An empty array is different from NULL.

Tip: EXPLAIN (ANALYZE, BUFFERS) Is Your Best Friend

For query debugging, always use EXPLAIN (ANALYZE, BUFFERS) instead of plain EXPLAIN. The BUFFERS option shows hit/miss rates for every node, revealing whether your indexes are actually in memory.

Tip: Partial Indexes Are Underutilized

CREATE INDEX ON orders (status) WHERE status = 'pending' creates a tiny index that covers only the rows your query needs. It's faster to scan and cheaper to maintain than a full-column index.

Gotcha: NULL Sorting Is Non-Obvious

By default, NULLs sort AFTER non-null values in ascending order. ORDER BY col DESC puts NULLs FIRST. Use NULLS LAST or NULLS FIRST to be explicit.

Senior Insight

PostgreSQL arrays are a unique feature that Laravel doesn't fully embrace. I've used integer arrays for lightweight many-to-many relationships, avoiding pivot tables for simple mappings. But there's a critical performance detail: querying array membership with ANY() uses a different index strategy than equality checks. A GIN index on the array column enables efficient @> (contains) queries, while a B-tree index is better for equality on the column itself.

Source: pganalyze Blog (https://pganalyze.com/blog), PostgreSQL Docs (https://www.postgresql.org/docs/current/), Crunchy Data Blog (https://www.crunchydata.com/blog)

────────────────────────────────────────────────────────
<-- back to posts