doesntmattr/mongodb-migrations
Laravel package for running MongoDB database migrations. Provides migration commands and structure similar to Laravel’s SQL migrations, helping you version and deploy MongoDB schema/index changes safely across environments.
Installation
composer require doesntmattr/mongodb-migrations
Add the service provider to config/app.php:
'providers' => [
// ...
DoesnTmattr\MongoDBMigrations\MongoDBMigrationsServiceProvider::class,
],
Publish Config & Migrations
php artisan vendor:publish --provider="DoesnTmattr\MongoDBMigrations\MongoDBMigrationsServiceProvider" --tag="migrations"
This generates:
config/mongodb-migrations.php (default: migrations table name, connection)database/migrations/mongodb/ (empty directory for MongoDB-specific migrations)First Migration Create a migration file:
php artisan make:migration create_users_collection --collection
Define schema in up():
public function up()
{
Schema::create('users', function (Blueprint $collection) {
$collection->index('email', ['unique' => true]);
$collection->index('created_at');
$collection->field('name', 'string');
$collection->field('email', 'string');
$collection->field('created_at', 'date');
});
}
Run migrations:
php artisan migrate
Schema Blueprints
Schema::create() for collections, Schema::table() for updates.field(name, type, [options]) (e.g., string, int, array, object).$collection->index('field', ['unique' => true, 'sparse' => true]).Schema::table('products', function (Blueprint $collection) {
$collection->field('price', 'decimal', ['precision' => 8, 'scale' => 2]);
$collection->index('category');
});
Rollbacks
down() to revert changes:
public function down()
{
Schema::dropIfExists('users');
}
php artisan migrate:rollback
Seeding Collections
Seeder classes with DB::collection('collection')->insert():
public function run()
{
DB::collection('users')->insert([
['name' => 'John', 'email' => 'john@example.com'],
['name' => 'Jane', 'email' => 'jane@example.com'],
]);
}
php artisan db:seed --class=UsersTableSeeder
Multi-Database Support
config/mongodb-migrations.php:
'connections' => [
'mongodb' => 'mongodb',
'secondary' => 'mongodb_secondary',
],
Schema::connection('secondary')->create('backups', ...);
Batch Migrations
2023_01_auth_migrations) and run selectively:
php artisan migrate --path=/database/migrations/mongodb/2023_01
| Use Case | Implementation | Command/Artisan |
|---|---|---|
| Create collection | Schema::create('collection', ...) |
php artisan migrate |
| Add index | $collection->index('field') |
php artisan migrate |
| Update field type | Schema::table()->field('field', 'new_type') |
php artisan migrate |
| Drop collection | Schema::dropIfExists('collection') |
php artisan migrate |
| Seed data | DB::collection()->insert() in Seeder |
php artisan db:seed |
| Reset migrations | Delete migrations table, run migrate:fresh |
php artisan migrate:fresh |
Schema Limitations
ALTER TABLE for adding/removing fields. Use down() to drop and up() to recreate.Index Conflicts
// Bad: Duplicate name
$collection->index('email');
$collection->index('email_1');
// Good: Unique names
$collection->index('email', ['name' => 'email_unique']);
$collection->index('email', ['name' => 'email_text']);
Connection Assumptions
mongodb connection. Explicitly specify if using multiple:
Schema::connection('custom_mongodb')->create('logs', ...);
Migration Table
migrations collection isn’t manually truncated.Field Type Mismatches
string → int) may corrupt existing data. Handle gracefully:
public function up()
{
Schema::table('users', function (Blueprint $collection) {
$collection->field('age', 'int', ['default' => 0]);
// Handle existing string data:
DB::collection('users')->updateMany(
['age' => ['$exists' => false]],
['$set' => ['age' => 0]]
);
});
}
Check Migration Status
php artisan migrate:status
Inspect Collection Schema
$collection = DB::collection('users');
$indexes = $collection->getIndexInfo();
dd($indexes);
Log Migration Steps
Add debug logs in up()/down():
\Log::info('Creating collection with indexes: ' . json_encode($indexes));
Test Locally with fresh
php artisan migrate:fresh --env=testing
migrations collection and reapplies all migrations.Custom Migration Events
Listen to migration events in EventServiceProvider:
protected $listen = [
'DoesnTmattr\MongoDBMigrations\Events\MigrationStarted' => [
\App\Listeners\LogMigrationStart::class,
],
];
Pre/Post-Migration Hooks
Override Migrator class to add logic:
class CustomMigrator extends \DoesnTmattr\MongoDBMigrations\Migrator
{
public function run($migration)
{
\Log::info("Running migration: {$migration->class}");
parent::run($migration);
}
}
Bind in AppServiceProvider:
public function register()
{
$this->app->bind(
\DoesnTmattr\MongoDBMigrations\Migrator::class,
\App\CustomMigrator::class
);
}
Custom Field Types
Extend Blueprint for domain-specific fields:
class CustomBlueprint extends \DoesnTmattr\MongoDBMigrations\Schema\Blueprint
{
public function embeddedDocument(string $name, array $schema)
{
$this->schema['$jsonSchema'] = [
'bsonType' => 'object',
'properties' => $schema,
];
return $this;
}
}
Use in migrations:
Schema::create('profiles', function (CustomBlueprint $collection) {
$collection->embeddedDocument('address', [
'street' => ['bsonType' => 'string'],
'city' => ['bsonType' => 'string'],
]);
});
Transaction Support (MongoDB 4.0+) Wrap migrations in sessions for atomicity:
public function up()
{
$session = DB::startSession();
try {
Schema::create('orders', function (Blueprint $collection) {
$collection->field('total', 'decimal');
});
DB::collection('orders')->insert([...]);
$session->commitTransaction();
} catch (\Exception $e) {
$session->abortTransaction();
throw $e;
}
}
How can I help you explore Laravel packages today?