Database Tutorial #19: ORMs vs Raw SQL — Prisma, SQLAlchemy, GORM

An ORM (Object-Relational Mapper) lets you work with your database using your programming language instead of SQL. It reduces boilerplate and prevents SQL injection. But ORMs also add abstraction — and abstraction can hide performance problems. When to Use an ORM vs Raw SQL Use an ORM when: You do standard CRUD (create, read, update, delete) You want type safety and IDE autocomplete You want schema migrations integrated with your code You are building fast and the query complexity is low Use raw SQL when: ...

August 9, 2026 · 5 min

Database Tutorial #17: SQLite — When and How to Use It

SQLite is the most deployed database in the world. It is built into every iPhone, Android device, and browser. You can use it as a production database for many real applications. What Makes SQLite Different SQLite is serverless and embedded. There is no separate database process. The entire database lives in a single file on disk. No installation, no configuration, no network The database is just a .db file you can copy, back up, or email Reads are fast — no network round trip Writes are serialized — only one writer at a time This makes SQLite perfect for: desktop apps, mobile apps, edge computing, testing, local development, CLIs, and read-heavy web apps with low write frequency. ...

August 8, 2026 · 4 min

Database Tutorial #15: Redis Pub/Sub and Streams

Redis has two messaging systems: Pub/Sub for fire-and-forget real-time events, and Streams for persistent, replayable event logs with consumer groups. Pub/Sub Pub/Sub is simple: publishers send messages to channels, subscribers receive them. Messages are not stored — if no subscriber is listening, the message is lost. # Terminal 1: Subscribe to a channel SUBSCRIBE notifications:user:1 # Terminal 2: Publish PUBLISH notifications:user:1 '{"type":"message","text":"Hello!"}' # Terminal 1 receives: "Hello!" Node.js Pub/Sub ioredis requires separate client connections for publishing and subscribing: ...

August 7, 2026 · 4 min

Database Tutorial #14: Redis Caching Patterns

A database query takes 50ms. The same query through Redis takes 0.1ms. Caching removes load from your database and makes your application faster. Why Cache? Reduce database load — fewer queries hit the database Lower latency — in-memory reads are 100-500x faster than disk reads Absorb traffic spikes — cache handles burst traffic without scaling the database Caching adds complexity. Only cache what you need to. Cache-Aside (Lazy Loading) The most common pattern. Read from cache first; fall back to database on miss. ...

August 7, 2026 · 5 min

Database Tutorial #13: Redis Setup and Data Types

Redis is an in-memory database. It is fast — reads and writes take microseconds. It is used for caching, sessions, rate limiting, pub/sub, queues, and leaderboards. Redis 8.0 (released May 2025) includes JSON, vector search, probabilistic data structures, and time series natively — no extensions needed. Setup with Docker docker run -d \ --name redis \ -p 6379:6379 \ redis:8 \ redis-server --save 60 1 --loglevel warning Connect with redis-cli: redis-cli # or with Docker: docker exec -it redis redis-cli Strings The most basic type. Strings can hold text, numbers, or binary data (up to 512 MB). ...

August 7, 2026 · 4 min

Database Tutorial #11: MongoDB Aggregation Pipeline

find() gets documents. The aggregation pipeline transforms them. It is MongoDB’s answer to SQL GROUP BY, JOIN, and window functions. How the Pipeline Works Documents flow through a sequence of stages. Each stage takes the output of the previous one as input. db.orders.aggregate([ { $match: { status: "delivered" } }, // Stage 1: filter { $group: { _id: "$user_id", total: { $sum: "$amount" } } }, // Stage 2: group { $sort: { total: -1 } }, // Stage 3: sort { $limit: 10 } // Stage 4: limit ]) $match — Filter Documents // Equivalent to WHERE in SQL db.orders.aggregate([ { $match: { status: "delivered", createdAt: { $gte: ISODate("2026-01-01"), $lt: ISODate("2027-01-01") } } } ]) Put $match as early as possible. It reduces the number of documents processed by later stages. ...

August 6, 2026 · 4 min

Database Tutorial #9: MongoDB Setup and CRUD

MongoDB stores data as documents — JSON-like objects with flexible structure. No fixed schema. No joins required for embedded data. This tutorial gets you up and running with MongoDB 8.0. Setup with Docker docker run -d \ --name mongodb \ -p 27017:27017 \ -e MONGO_INITDB_ROOT_USERNAME=admin \ -e MONGO_INITDB_ROOT_PASSWORD=password \ mongodb/mongodb-community-server:8.0-ubi8 Connect with mongosh: mongosh "mongodb://admin:password@localhost:27017" mongosh Basics // Show databases show dbs // Switch to (or create) a database use myapp // Show collections show collections // Create a collection explicitly (optional — auto-created on first insert) db.createCollection("users") Documents and Collections In MongoDB: ...

August 5, 2026 · 4 min

Database Tutorial #6: PostgreSQL Transactions and Concurrency

Two users buy the last item in stock at the same time. Your app charges a card, then the payment service fails. A report runs while someone is editing data. These are concurrency problems. Transactions solve them. What is a Transaction? A transaction is a group of SQL statements that execute as one unit. Either all succeed or none apply. BEGIN; UPDATE accounts SET balance = balance - 100 WHERE id = 1; UPDATE accounts SET balance = balance + 100 WHERE id = 2; COMMIT; If anything fails between BEGIN and COMMIT, call ROLLBACK to undo everything: ...

August 4, 2026 · 6 min

Database Tutorial #5: PostgreSQL JSON and Full-Text Search

PostgreSQL is not just a relational database. It has first-class JSON support and a powerful full-text search engine built in. No separate search service needed for most applications. jsonb vs json PostgreSQL has two JSON types. Always use jsonb. json jsonb Storage Text, preserves whitespace Binary, compressed Indexing Not indexable GIN index supported Query speed Slow (re-parses on each read) Fast Key order Preserved Not preserved CREATE TABLE products ( id SERIAL PRIMARY KEY, name TEXT NOT NULL, metadata JSONB ); INSERT INTO products (name, metadata) VALUES ('Laptop', '{"brand": "Dell", "specs": {"ram": 16, "ssd": 512}, "tags": ["electronics", "work"]}'), ('Phone', '{"brand": "Apple", "specs": {"ram": 8, "ssd": 256}, "tags": ["electronics", "mobile"]}'); jsonb Query Operators -- -> returns a JSON value (keeps JSON type) SELECT metadata -> 'brand' FROM products; -- "Dell" -- ->> returns text SELECT metadata ->> 'brand' FROM products; -- Dell -- #> for nested paths (returns JSON) SELECT metadata #> '{specs, ram}' FROM products; -- 16 -- #>> for nested paths (returns text) SELECT metadata #>> '{specs, ram}' FROM products; -- 16 -- @> containment: does the left side contain the right? SELECT * FROM products WHERE metadata @> '{"brand": "Dell"}'; -- ? key exists SELECT * FROM products WHERE metadata ? 'brand'; -- ?| any of these keys exist SELECT * FROM products WHERE metadata ?| ARRAY['brand', 'price']; -- ?& all of these keys exist SELECT * FROM products WHERE metadata ?& ARRAY['brand', 'specs']; Updating jsonb -- Replace a key UPDATE products SET metadata = jsonb_set(metadata, '{brand}', '"Lenovo"') WHERE id = 1; -- Add a new key UPDATE products SET metadata = metadata || '{"price": 999}' WHERE id = 1; -- Remove a key UPDATE products SET metadata = metadata - 'price' WHERE id = 1; -- Update nested value UPDATE products SET metadata = jsonb_set(metadata, '{specs, ram}', '32') WHERE id = 1; Indexing jsonb A GIN index makes containment queries (@>) and key existence (?) fast: ...

August 4, 2026 · 5 min

Database Tutorial #4: PostgreSQL Indexing and Performance

Your query works. But it is slow. The fix is almost always an index. This tutorial covers how indexes work in PostgreSQL, when to use them, and how to confirm they are actually helping. How a B-tree Index Works Without an index, PostgreSQL reads every row in the table to find matches. This is called a sequential scan. For a table with 10 million rows, that means 10 million comparisons. ...

August 4, 2026 · 5 min