Node.js Database: Complete Theory & Practice Guide

Core database theory + practical PostgreSQL, MongoDB, MySQL patterns for production Node.js apps.

Table of Contents

  1. Theory: Database Fundamentals
  2. Theory: SQL vs NoSQL
  3. Theory: Connection Management
  4. Theory: Query Optimization
  5. Basic: PostgreSQL with node-postgres
  6. Basic: MongoDB with Mongoose
  7. Basic: MySQL with mysql2
  8. Advanced: Transaction & ACID
  9. Advanced: Migration & Schema Management
  10. Best Practices
  11. Interview Q&A + MCQ
  12. Contextual Learning Links

1. Theory: Database Fundamentals

A database is an organized collection of structured information stored electronically. In Node.js applications, databases persist data beyond the application's lifecycle.

OperationSQLMongoDBHTTP Equivalent
CreateINSERTinsertOne()POST
ReadSELECTfindOne()GET
UpdateUPDATEupdateOne()PUT/PATCH
DeleteDELETEdeleteOne()DELETE
const databaseConcepts = {
  Index: { definition: 'Faster lookup', tradeoff: 'Read speed vs write overhead' },
  Transaction: { definition: 'All-or-nothing operations', properties: 'ACID' },
  ConnectionPool: { definition: 'Reusable connections', benefit: 'Lower latency' },
  QueryPlan: { definition: 'Optimizer execution strategy', tool: 'EXPLAIN' }
};

2. Theory: SQL vs NoSQL

AspectSQLNoSQL
Data ModelTablesDocuments
SchemaRigidFlexible
RelationshipsJOINsEmbedding/refs
ACIDStrongUsually document-level
const databaseSelectionGuide = {
  chooseSQLWhen: ['Complex joins', 'Strict transactions', 'Predictable schema'],
  chooseNoSQLWhen: ['Rapid schema change', 'Document-heavy data', 'Horizontal scale'],
  hybridApproach: ['PostgreSQL + JSONB', 'Polyglot persistence']
};

3. Theory: Connection Management

const poolSizingTheory = {
  formula: 'maxPoolSize = (coreCount × 2) + spindleCount',
  warning: '(maxPoolSize × instances) < database max_connections'
};
const connectionStrings = {
  PostgreSQL: 'postgresql://user:password@host:5432/db?ssl=true&pool_size=10',
  MySQL: 'mysql://user:password@host:3306/db?connectionLimit=10',
  MongoDB: 'mongodb://user:password@host:27017/db?maxPoolSize=10'
};

4. Theory: Query Optimization

-- Useful index patterns
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_orders_user_status ON orders(user_id, status);
CREATE UNIQUE INDEX idx_users_email_unique ON users(email);
CREATE INDEX idx_active_users ON users(id) WHERE active = true;
const optimizationTechniques = {
  good: 'SELECT id,name,email FROM users WHERE id = $1',
  avoid: 'SELECT *',
  use: ['EXPLAIN', 'Parameterized queries', 'Batch queries']
};

5. Basic: PostgreSQL with node-postgres

npm install pg
const { Pool } = require('pg');
const pool = new Pool({
  host: process.env.DB_HOST || 'localhost',
  port: process.env.DB_PORT || 5432,
  database: process.env.DB_NAME || 'myapp',
  user: process.env.DB_USER || 'postgres',
  password: process.env.DB_PASSWORD,
  max: 20,
  idleTimeoutMillis: 30000,
  connectionTimeoutMillis: 2000
});

6. Basic: MongoDB with Mongoose

npm install mongoose
const userSchema = new mongoose.Schema({
  name: { type: String, required: true, trim: true },
  email: { type: String, required: true, unique: true, lowercase: true },
  passwordHash: { type: String, required: true, select: false },
  role: { type: String, enum: ['user', 'moderator', 'admin'], default: 'user' }
}, { timestamps: true });

7. Basic: MySQL with mysql2

npm install mysql2
const mysql = require('mysql2');
const pool = mysql.createPool({
  host: process.env.MYSQL_HOST || 'localhost',
  port: process.env.MYSQL_PORT || 3306,
  database: process.env.MYSQL_DATABASE || 'myapp',
  user: process.env.MYSQL_USER || 'root',
  password: process.env.MYSQL_PASSWORD,
  waitForConnections: true,
  connectionLimit: 10
}).promise();

8. Advanced: Transaction & ACID

const acidProperties = {
  Atomicity: 'All operations succeed or all fail',
  Consistency: 'Data remains valid',
  Isolation: 'Transactions do not interfere',
  Durability: 'Committed writes survive crashes'
};
// PostgreSQL transfer transaction (condensed)
await client.query('BEGIN');
await client.query('UPDATE accounts SET balance = balance - $1 WHERE user_id = $2', [amount, fromUserId]);
await client.query('UPDATE accounts SET balance = balance + $1 WHERE user_id = $2', [amount, toUserId]);
await client.query('COMMIT');

9. Advanced: Migration & Schema Management

npm install node-pg-migrate pg
// migrations/001_create_users_table.js
exports.up = async (pgm) => {
  pgm.createTable('users', {
    id: { type: 'serial', primaryKey: true },
    email: { type: 'varchar(255)', notNull: true, unique: true },
    created_at: { type: 'timestamp', default: pgm.func('NOW()') }
  });
  pgm.createIndex('users', 'email');
};
exports.down = async (pgm) => pgm.dropTable('users');
// MongoDB migration shape
async function up(db) {
  await db.createCollection('users');
  await db.collection('users').createIndex({ email: 1 }, { unique: true });
}
async function down(db) {
  await db.collection('users').drop();
}

10. Best Practices

const queryBestPractices = {
  good: [
    'Use pooling',
    'Use parameterized queries',
    'Index WHERE/JOIN columns',
    'Monitor slow queries with EXPLAIN',
    'Set query and connection timeouts'
  ]
};
// Quick commands
// PostgreSQL: psql -U postgres -d myapp
// MongoDB: mongosh
// MySQL: mysql -u root -p myapp
// Migrations: npm run migrate up

10 Interview Questions + 10 MCQs

1Why should Node.js apps use connection pools?easy
Answer: Pools reduce connection creation overhead and stabilize latency under concurrent load.
2SQL vs NoSQL - when would you pick SQL?easy
Answer: Prefer SQL when relationships, joins, and strict ACID guarantees are essential.
3What is ACID in one line?easy
Answer: A transaction model ensuring Atomicity, Consistency, Isolation, and Durability.
4What causes N+1 query problems?medium
Answer: Fetching parent rows and then querying child data row-by-row in loops.
5How do you verify index usage?medium
Answer: Use `EXPLAIN`/`EXPLAIN ANALYZE` and inspect scan/join strategies and row estimates.
6Why use parameterized queries?easy
Answer: They prevent SQL injection and improve safety for dynamic input.
7What is a good pool sizing rule of thumb?medium
Answer: Start around 8-20 per app instance and ensure total across instances stays below DB limits.
8Why are transactions critical for money movement?hard
Answer: They guarantee both debit and credit succeed together or rollback entirely.
9What are migrations used for?easy
Answer: Version controlling schema changes with repeatable up/down operations.
10What is one fast win for slow queries?medium
Answer: Index selective filter columns and avoid `SELECT *` on large tables.

10 Database MCQs

1

Which is safest for dynamic SQL input?

AString concatenation
BParameterized query
CFrontend regex only
DURL encoding values
Explanation: Parameterized queries keep SQL structure separate from data input.
2

ACID property for "all-or-nothing" is:

AConsistency
BIsolation
CAtomicity
DDurability
Explanation: Atomicity ensures the transaction fully commits or fully rolls back.
3

Main benefit of connection pooling:

AZero memory usage
BNo DB limits apply
CReduced connection overhead
DAuto schema migration
Explanation: Reusing connections avoids costly open/close cycles per request.
4

What usually indicates N+1 queries?

ASingle JOIN query
BLoop issuing one query per item
CPrepared statements
DConnection timeout
Explanation: N+1 happens when an initial query is followed by many per-row queries.
5

Best tool to inspect SQL execution strategy:

AEXPLAIN / EXPLAIN ANALYZE
BSELECT *
CSHOW TABLES
DDESCRIBE only
Explanation: EXPLAIN reveals chosen scans, joins, and estimates.
6

Which index helps multi-column filtering order-aware?

AComposite index
BRandom index
CText-only index
DNo index
Explanation: Composite indexes optimize predicates that match indexed column order.
7

In transactions, `ROLLBACK` means:

AApply all pending changes
BRevert uncommitted transaction changes
CBackup database
DRestart DB server
Explanation: ROLLBACK discards in-flight transactional writes.
8

Why use migrations in teams?

AAvoid version control
BTrack and apply schema changes consistently
CRemove constraints
DDisable rollbacks
Explanation: Migrations provide reproducible schema versioning across environments.
9

Typical SQL engine best for strict relational workloads:

APostgreSQL
BPlain JSON files
CRedis-only
DCSV sheets
Explanation: PostgreSQL is widely used for transactional relational systems.
10

A strong production DB baseline includes:

ANo monitoring
BPooling, indexes, parameterized queries, slow query monitoring
CHardcoded credentials
DUnlimited pool size
Explanation: These controls provide security, reliability, and performance fundamentals.