Database Migrations
Learn how to use the built-in migration tools for database schema changes.
Introduction to Migrations
Database migrations are a way to manage changes to your database schema over time. @inceptools/db provides built-in migration tools for both MongoDB and SQL databases.
Migrations allow you to:
- Track changes to your database schema
- Apply changes incrementally
- Roll back changes if needed
- Collaborate with team members on database changes
- Deploy database changes consistently across environments
MongoDB Migration Setup
import { MongoService, SUPPORTED_DBS } from "@inceptools/db";
import mongoose from "mongoose";
// Create a MongoDB service instance
const mongoService = new MongoService({
type: SUPPORTED_DBS.MONGO_DB,
connectionString: "mongodb://localhost:27017/myapp",
models: {},
});
// Connect to MongoDB
await mongoService.connect();
// Get the migration service
const migrationService = mongoService.migrationService;
// Initialize migrations (creates the migrations collection if it doesn't exist)
await migrationService.init();
// Generate a new migration
await migrationService.generateMigration("add-user-roles");
// This creates a file in ./migrations/mongodb/[timestamp]_add-user-roles.js
// Apply pending migrations
await migrationService.migrate();
// Roll back the last applied migration
await migrationService.rollback();
// Get migration status
const status = await migrationService.status();
console.log(status);
MongoDB Migration File Structure
// migrations/mongodb/20230101000000_add-user-roles.js
module.exports = {
async up(db) {
// Update schema
await db.collection('users').updateMany({}, {
$set: { roles: ['user'] }
});
},
async down(db) {
// Revert changes
await db.collection('users').updateMany({}, {
$unset: { roles: "" }
});
}
};
MongoDB Migration Examples
Example 1
Adding a field with a default value
module.exports = {
async up(db) {
await db.collection('users').updateMany(
{ isActive: { $exists: false } },
{ $set: { isActive: true } }
);
},
async down(db) {
await db.collection('users').updateMany(
{},
{ $unset: { isActive: "" } }
);
}
};
Example 2
Creating an index
module.exports = {
async up(db) {
await db.collection('users').createIndex(
{ email: 1 },
{ unique: true }
);
},
async down(db) {
await db.collection('users').dropIndex('email_1');
}
};
Example 3
Renaming a field
module.exports = {
async up(db) {
await db.collection('users').updateMany(
{},
{ $rename: { "name": "fullName" } }
);
},
async down(db) {
await db.collection('users').updateMany(
{},
{ $rename: { "fullName": "name" } }
);
}
};
Example 4
Creating a new collection
module.exports = {
async up(db) {
await db.createCollection('orders');
await db.collection('orders').createIndex(
{ userId: 1, createdAt: -1 }
);
},
async down(db) {
await db.collection('orders').drop();
}
};
Migration Best Practices
- Keep migrations small and focused: Each migration should make a single logical change to the database schema.
- Always implement the down method: This allows you to roll back changes if needed.
- Test migrations before applying them to production: Run migrations in a development or staging environment first.
- Use transactions for SQL migrations: This ensures that all changes in a migration are applied atomically.
- Version control your migrations: Commit migration files to your version control system.
- Never modify existing migration files: Once a migration has been applied, create a new migration to make additional changes.
- Document complex migrations: Add comments to explain the purpose and impact of complex changes.
Migration CLI (Coming Soon)
Coming Soon
Command Line InterfaceIn a future release, @inceptools/db will include a command-line interface for managing migrations:
# Generate a new migration
npx inceptools migrate:generate --name add-user-roles --type mongodb
# Apply pending migrations
npx inceptools migrate:up
# Roll back the last migration
npx inceptools migrate:down
# Get migration status
npx inceptools migrate:status
Stay tuned for updates on the migration CLI!