# Laravel MongoDB Laravel MongoDB is a package that adds MongoDB functionality to the Eloquent ORM and Query Builder for Laravel. It extends the original Laravel classes to provide seamless MongoDB integration while maintaining the familiar Laravel API. This package supports Laravel 10.x, 11.x, and 12.x, and is compatible with PHP 8.1+ and MongoDB PHP extension 1.21+. The package provides a complete MongoDB integration including Eloquent models, relationships (including embedded documents), schema migrations, queue support, cache driver, session handling, and GridFS filesystem adapter. It enables cross-database relationships between SQL and MongoDB databases through hybrid relations, making it ideal for applications that need to leverage both database types. ## Database Configuration Configure a MongoDB connection in your Laravel application's database configuration file. ```php // config/database.php 'connections' => [ 'mongodb' => [ 'driver' => 'mongodb', 'dsn' => env('MONGODB_URI', 'mongodb://localhost:27017'), 'database' => env('MONGODB_DATABASE', 'homestead'), 'options' => [ 'appName' => 'my-laravel-app', ], ], // Alternative configuration with host/port 'mongodb_alt' => [ 'driver' => 'mongodb', 'host' => env('MONGODB_HOST', '127.0.0.1'), 'port' => env('MONGODB_PORT', 27017), 'database' => env('MONGODB_DATABASE', 'homestead'), 'username' => env('MONGODB_USERNAME', ''), 'password' => env('MONGODB_PASSWORD', ''), 'options' => [ 'database' => 'admin', // Authentication database ], ], ], ``` ## Eloquent Model Definition Create MongoDB models by extending the MongoDB Model class which provides all standard Eloquent functionality with MongoDB-specific features. ```php 'integer', 'is_admin' => 'boolean', 'settings' => 'array', 'price' => 'decimal:2', // Stored as MongoDB Decimal128 ]; // Define relationships public function posts() { return $this->hasMany(Post::class); } public function role() { return $this->belongsTo(Role::class); } } ``` ## Basic Query Operations Perform CRUD operations using the familiar Eloquent and Query Builder syntax with MongoDB-specific operators. ```php use App\Models\User; // Create a new document $user = User::create([ 'name' => 'John Doe', 'email' => 'john@example.com', 'age' => 30, 'tags' => ['developer', 'php'], 'address' => [ 'city' => 'New York', 'zip' => '10001', ], ]); // Find by ID (supports both 'id' and '_id') $user = User::find('507f1f77bcf86cd799439011'); // Basic where queries $users = User::where('age', '>', 25) ->where('tags', 'developer') ->orderBy('name', 'asc') ->limit(10) ->get(); // Using MongoDB operators $users = User::where('age', 'exists', true) ->where('tags', 'size', 2) ->where('name', 'regex', '/^John/i') ->get(); // Query nested documents (dot notation) $users = User::where('address.city', 'New York')->get(); // Update documents User::where('age', '<', 18)->update(['status' => 'minor']); // Increment/decrement values $user->increment('login_count'); $user->decrement('credits', 10); // Delete documents User::where('status', 'inactive')->delete(); $user->delete(); // Upsert operation User::upsert( [ ['email' => 'john@example.com', 'name' => 'John'], ['email' => 'jane@example.com', 'name' => 'Jane'], ], ['email'], // Unique by ['name'] // Update these fields ); ``` ## Array and Embedded Document Operations Work with MongoDB arrays using push, pull, and unset operations directly on model instances. ```php use App\Models\User; $user = User::find($id); // Push values to an array field $user->push('tags', 'mongodb'); $user->push('tags', ['laravel', 'eloquent']); // Push multiple values // Push unique values only (no duplicates) $user->push('tags', 'mongodb', true); // Pull (remove) values from an array $user->pull('tags', 'php'); $user->pull('tags', ['old-tag', 'deprecated']); // Unset (remove) fields from document $user->unset('temporary_field'); $user->unset(['field1', 'field2']); // Update nested document fields $user->setAttribute('address.city', 'Los Angeles'); $user->setAttribute('settings.notifications.email', true); $user->save(); // Using query builder for array operations User::where('_id', $id)->push('tags', 'new-tag'); User::where('_id', $id)->pull('tags', 'old-tag'); // Remove fields using query builder User::where('status', 'deleted')->drop(['sensitive_data', 'temp_field']); ``` ## Relationships Define and work with relationships between MongoDB models including embedded documents. ```php hasMany(Post::class); } // Many-to-Many relationship (stores IDs in array) public function roles() { return $this->belongsToMany(Role::class, null, 'user_ids', 'role_ids'); } // Embedded documents (one-to-many) public function addresses() { return $this->embedsMany(Address::class); } // Embedded document (one-to-one) public function profile() { return $this->embedsOne(Profile::class); } // Polymorphic relations public function comments() { return $this->morphMany(Comment::class, 'commentable'); } } // Usage examples $user = User::find($id); // Query relationships $posts = $user->posts()->where('published', true)->get(); // Eager loading $users = User::with(['posts', 'roles'])->get(); // Working with embedded documents $user->addresses()->create([ 'street' => '123 Main St', 'city' => 'New York', 'zip' => '10001', ]); // Save embedded document $address = new Address(['city' => 'Boston']); $user->addresses()->save($address); // Associate embedded document (without saving to DB) $user->addresses()->associate($address); $user->save(); // Dissociate embedded document $user->addresses()->dissociate($address); ``` ## Hybrid Relations (Cross-Database) Define relationships between SQL (MySQL, PostgreSQL) and MongoDB models using the HybridRelations trait. ```php hasOne(MongoProfile::class); } public function mongoPosts() { return $this->hasMany(MongoPost::class, 'user_id'); } } // MongoDB model referencing SQL model class MongoPost extends \MongoDB\Laravel\Eloquent\Model { protected $connection = 'mongodb'; public function author() { return $this->belongsTo(SqlUser::class, 'user_id'); } } // Usage $sqlUser = SqlUser::find(1); $mongoPosts = $sqlUser->mongoPosts; // MongoDB documents $mongoPost = MongoPost::first(); $author = $mongoPost->author; // SQL record ``` ## Aggregation Framework Use MongoDB's aggregation framework through the fluent aggregation builder or raw aggregation pipelines. ```php use App\Models\Order; use MongoDB\Builder\Search; // Using the aggregation builder $results = Order::aggregate() ->match(['status' => 'completed']) ->group([ '_id' => '$customer_id', 'total_spent' => ['$sum' => '$amount'], 'order_count' => ['$sum' => 1], 'avg_order' => ['$avg' => '$amount'], ]) ->sort(['total_spent' => -1]) ->limit(10) ->get(); // Aggregation with unwind for subdocument arrays $results = Order::aggregate() ->match(['date' => ['$gte' => $startDate]]) ->unwind('$items') ->group([ '_id' => '$items.product_id', 'quantity' => ['$sum' => '$items.quantity'], 'revenue' => ['$sum' => ['$multiply' => ['$items.price', '$items.quantity']]], ]) ->get(); // Basic aggregation functions via Query Builder $total = Order::where('status', 'completed')->sum('amount'); $avg = Order::where('status', 'completed')->avg('amount'); $max = Order::where('status', 'completed')->max('amount'); $count = Order::where('status', 'completed')->count(); // Group by with aggregation $salesByMonth = Order::raw(function ($collection) { return $collection->aggregate([ ['$match' => ['status' => 'completed']], ['$group' => [ '_id' => ['$month' => '$created_at'], 'total' => ['$sum' => '$amount'], 'count' => ['$sum' => 1], ]], ['$sort' => ['_id' => 1]], ]); }); ``` ## Atlas Search and Vector Search Perform full-text and vector similarity searches using MongoDB Atlas Search indexes. ```php use App\Models\Product; use MongoDB\Builder\Search; // Full-text search (requires Atlas Search index) $results = Product::search( operator: Search::text( query: 'wireless headphones', path: ['name', 'description'] ), index: 'default', highlight: ['path' => ['name', 'description']] ); // Autocomplete search $suggestions = Product::query() ->autocomplete( path: 'name', query: 'wire', fuzzy: true, // Allow typos tokenOrder: 'sequential' ); // Compound search with multiple operators $results = Product::search( operator: Search::compound( must: [ Search::text(query: 'laptop', path: 'category'), ], should: [ Search::text(query: 'gaming', path: 'tags'), ], filter: [ Search::range(path: 'price', gte: 500, lte: 2000), ] ), index: 'products_search' ); // Vector Search for semantic similarity (requires Atlas Vector Search index) $results = Product::vectorSearch( index: 'product_embeddings', path: 'embedding', queryVector: $embeddingVector, // Array of floats from your ML model limit: 10, numCandidates: 100 ); // Vector search with pre-filter $results = Product::vectorSearch( index: 'product_embeddings', path: 'embedding', queryVector: $embeddingVector, limit: 10, filter: ['category' => 'electronics'] ); ``` ## Schema and Indexes Create and manage MongoDB collections and indexes using Laravel migrations. ```php create('products', function (Blueprint $collection) { $collection->create([ 'capped' => true, 'size' => 1048576, // 1MB 'max' => 1000, ]); }); // Create indexes Schema::connection('mongodb')->table('users', function (Blueprint $collection) { // Single field index $collection->index('email'); // Unique index $collection->unique('email'); // Compound index $collection->index(['status' => 1, 'created_at' => -1]); // Sparse index (only indexes documents with the field) $collection->sparse('nickname'); // TTL index (auto-delete documents after specified seconds) $collection->expire('session_token', 3600); // Text index for full-text search $collection->index(['name' => 'text', 'description' => 'text']); // Geospatial index $collection->geospatial('location', '2dsphere'); // Sparse and unique combined $collection->sparse_and_unique('api_key'); }); // Create Atlas Search index Schema::connection('mongodb')->table('products', function (Blueprint $collection) { $collection->searchIndex([ 'mappings' => [ 'dynamic' => false, 'fields' => [ 'name' => ['type' => 'string', 'analyzer' => 'lucene.standard'], 'description' => ['type' => 'string'], 'price' => ['type' => 'number'], ], ], ], 'products_search'); }); // Create Vector Search index Schema::connection('mongodb')->table('products', function (Blueprint $collection) { $collection->vectorSearchIndex([ 'fields' => [ [ 'type' => 'vector', 'path' => 'embedding', 'numDimensions' => 1536, 'similarity' => 'cosine', ], [ 'type' => 'filter', 'path' => 'category', ], ], ], 'product_embeddings'); }); // JSON Schema validation Schema::connection('mongodb')->table('orders', function (Blueprint $collection) { $collection->jsonSchema([ 'bsonType' => 'object', 'required' => ['customer_id', 'items', 'total'], 'properties' => [ 'customer_id' => ['bsonType' => 'objectId'], 'items' => [ 'bsonType' => 'array', 'minItems' => 1, ], 'total' => [ 'bsonType' => 'decimal', 'minimum' => 0, ], ], ], validationLevel: 'moderate', validationAction: 'warn'); }); } public function down(): void { Schema::connection('mongodb')->table('users', function (Blueprint $collection) { $collection->dropIndex('email_1'); $collection->dropIndexIfExists(['status_1_created_at_-1']); }); Schema::connection('mongodb')->dropIfExists('products'); } }; ``` ## Transactions Execute operations within MongoDB transactions for ACID compliance (requires replica set). ```php use Illuminate\Support\Facades\DB; use App\Models\Account; // Using the transaction method with automatic retry $result = DB::connection('mongodb')->transaction(function ($connection) { $sender = Account::where('user_id', 1)->first(); $receiver = Account::where('user_id', 2)->first(); $sender->decrement('balance', 100); $receiver->increment('balance', 100); return [ 'sender_balance' => $sender->balance, 'receiver_balance' => $receiver->balance, ]; }, attempts: 3); // Manual transaction control $connection = DB::connection('mongodb'); try { $connection->beginTransaction(); $order = Order::create([ 'customer_id' => $customerId, 'total' => $total, ]); Inventory::where('product_id', $productId) ->decrement('quantity', $quantity); $connection->commit(); } catch (\Exception $e) { $connection->rollBack(); throw $e; } ``` ## Queue Driver Use MongoDB as a queue backend for Laravel's queue system. ```php // config/queue.php 'connections' => [ 'mongodb' => [ 'driver' => 'mongodb', 'connection' => 'mongodb', 'table' => 'jobs', 'queue' => 'default', 'retry_after' => 90, ], ], // Dispatch jobs to MongoDB queue dispatch(new ProcessOrder($order))->onConnection('mongodb'); // Create the jobs collection with index Schema::connection('mongodb')->table('jobs', function ($collection) { $collection->index(['queue' => 1, 'reserved' => 1, 'available_at' => 1]); }); ``` ## Cache Driver Use MongoDB as a cache backend with support for atomic locks. ```php // config/cache.php 'stores' => [ 'mongodb' => [ 'driver' => 'mongodb', 'connection' => 'mongodb', 'collection' => 'cache', 'lock_connection' => 'mongodb', 'lock_collection' => 'cache_locks', 'lock_lottery' => [2, 100], // Cleanup probability 'lock_timeout' => 86400, ], ], // Usage Cache::store('mongodb')->put('key', 'value', 3600); $value = Cache::store('mongodb')->get('key'); // Atomic locks $lock = Cache::store('mongodb')->lock('processing-order-' . $orderId, 10); if ($lock->get()) { try { // Process order exclusively } finally { $lock->release(); } } // Create TTL index for automatic expiration Schema::connection('mongodb')->table('cache', function ($collection) { $collection->expire('expires_at', 0); }); ``` ## GridFS Filesystem Store and retrieve files using MongoDB GridFS through Laravel's filesystem abstraction. ```php // config/filesystems.php 'disks' => [ 'gridfs' => [ 'driver' => 'gridfs', 'connection' => 'mongodb', 'database' => 'files_db', // Optional, uses connection default 'bucket' => 'fs', // GridFS bucket name 'prefix' => '', // Optional path prefix 'read-only' => false, ], ], // Usage use Illuminate\Support\Facades\Storage; // Store files Storage::disk('gridfs')->put('documents/report.pdf', $content); Storage::disk('gridfs')->putFileAs('images', $uploadedFile, 'photo.jpg'); // Retrieve files $content = Storage::disk('gridfs')->get('documents/report.pdf'); $exists = Storage::disk('gridfs')->exists('documents/report.pdf'); $url = Storage::disk('gridfs')->url('documents/report.pdf'); // Stream large files $stream = Storage::disk('gridfs')->readStream('videos/large-file.mp4'); // Delete files Storage::disk('gridfs')->delete('documents/report.pdf'); // List files $files = Storage::disk('gridfs')->files('documents'); $allFiles = Storage::disk('gridfs')->allFiles('documents'); ``` ## Raw Queries and MongoDB Collection Access Access the underlying MongoDB collection for advanced operations not covered by the query builder. ```php use App\Models\User; use Illuminate\Support\Facades\DB; // Get raw MongoDB collection via model $users = User::raw(function ($collection) { return $collection->find( ['status' => 'active'], ['projection' => ['name' => 1, 'email' => 1]] ); }); // Access collection directly $collection = DB::connection('mongodb')->getCollection('users'); $result = $collection->findOneAndUpdate( ['email' => 'john@example.com'], ['$set' => ['last_login' => new \MongoDB\BSON\UTCDateTime()]], ['returnDocument' => \MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_AFTER] ); // Bulk write operations $collection->bulkWrite([ ['insertOne' => [['name' => 'User 1', 'status' => 'active']]], ['updateOne' => [ ['email' => 'user@example.com'], ['$set' => ['status' => 'verified']], ]], ['deleteMany' => [['status' => 'inactive']]], ]); // Debug query - dump MQL User::where('age', '>', 25)->dump(); // Outputs MongoDB query User::where('age', '>', 25)->toMql(); // Returns array representation // whereRaw with MongoDB query syntax $users = User::whereRaw([ 'age' => ['$gte' => 18, '$lte' => 65], 'roles' => ['$in' => ['admin', 'moderator']], ])->get(); ``` Laravel MongoDB provides a comprehensive solution for integrating MongoDB into Laravel applications while preserving the elegant Eloquent API developers expect. The package supports all major Laravel features including authentication, queues, caching, sessions, and file storage through native MongoDB implementations. For applications requiring the flexibility of document databases alongside traditional SQL databases, Laravel MongoDB's hybrid relations enable seamless cross-database relationships. Combined with support for MongoDB Atlas features like full-text search and vector search, the package enables building modern applications that leverage MongoDB's capabilities while maintaining Laravel's developer experience.