doctrine/mongodb-odm
Doctrine MongoDB ODM is an object document mapper for PHP that brings Doctrine-style persistence to MongoDB. Define documents with metadata, map fields and relations, run queries, and handle unit of work, identity map, and migrations for MongoDB apps.
Installation
composer require doctrine/mongodb-odm
composer require mongodb/mongodb
Configure MongoDB Connection
Add to config/database.php:
'connections' => [
'mongodb' => [
'driver' => 'mongodb',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', 27017),
'database' => env('DB_DATABASE', 'laravel'),
'username' => env('DB_USERNAME', ''),
'password' => env('DB_PASSWORD', ''),
'options' => [
'connect' => true,
],
],
],
Define a Document Model
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
#[ODM\Document(collection: "users")]
class User
{
#[ODM\Id]
private ?string $id = null;
#[ODM\Field(type: "string")]
private string $name;
// Getters/Setters...
}
Register ODM Service Provider
In config/app.php:
'providers' => [
Doctrine\ODM\MongoDB\MongoDBServiceProvider::class,
],
First Query
use Doctrine\ODM\MongoDB\DocumentManager;
$dm = app(DocumentManager::class);
$user = $dm->find(User::class, 'some-id');
// Create
$user = new User();
$user->setName('John Doe');
$dm->persist($user);
$dm->flush();
// Read
$user = $dm->find(User::class, $user->getId());
// Update
$user->setName('Updated Name');
$dm->flush();
// Delete
$dm->remove($user);
$dm->flush();
$queryBuilder = $dm->createQueryBuilder(User::class)
->field('name')->equals('John Doe')
->field('age')->gt(18)
->sort('name', 'ASC')
->limit(10);
$users = $queryBuilder->getQuery()->execute();
#[ODM\EmbeddedDocument]
class Address
{
#[ODM\Field(type: "string")]
private string $street;
// ...
}
#[ODM\Document]
class User
{
#[ODM\EmbedOne(targetDocument: Address::class)]
private ?Address $address = null;
}
#[ODM\Document]
class Post
{
#[ODM\ReferenceOne(targetDocument: User::class)]
private ?User $author = null;
}
$pipeline = [
['$match' => ['age' => ['$gt' => 18]]],
['$group' => ['_id' => '$name', 'count' => ['$sum' => 1]]],
];
$results = $dm->createAggregationBuilder(User::class)
->pipeline($pipeline)
->getQuery()
->execute();
Create a facade for cleaner syntax:
// app/Facades/MongoDB.php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class MongoDB extends Facade
{
protected static function getFacadeAccessor() { return 'mongodb'; }
}
Register in AppServiceProvider:
public function register()
{
$this->app->singleton('mongodb', function () {
return app(DocumentManager::class);
});
}
Usage:
$user = MongoDB::find(User::class, 'id');
Use doctrine/mongodb-odm-module for schema migrations:
composer require doctrine/mongodb-odm-module
php artisan doctrine:mongo:schema:update --complete
use Doctrine\ODM\MongoDB\Events;
$dm->getEventManager()->addEventListener(
Events::postPersist,
function ($event) {
// Post-save logic
}
);
Extend Type for custom field types:
use Doctrine\ODM\MongoDB\Types\Type;
class CustomType extends Type
{
public function convertToPHPValue($value)
{
return json_decode($value, true);
}
public function convertToDatabaseValue($value)
{
return json_encode($value);
}
}
Register in config/doctrine-mongodb-odm.php:
'types' => [
'custom' => 'App\\Types\\CustomType',
],
Lazy Loading Issues
'use_native_lazy_objects' => true,
QueryBuilder Caching
php artisan doctrine:mongo:cache:clear-metadata
Case Sensitivity in Field Names
Transactions
Index Management
#[ODM\Index(name: "name_idx", fields: ["name" => "text"])]
Enable Query Logging
$dm->getConfiguration()->setSQLLogger(new \Doctrine\ODM\MongoDB\Logging\EchoSQLLogger());
Check Hydration
useNativeLazyObjects: true to avoid proxy-related issues.Schema Validation
php artisan doctrine:mongo:schema:validate
Projection Queries
$queryBuilder->fields(['name' => true, 'email' => true]);
Batch Operations
$dm->createQueryBuilder(User::class)
->field('status')->equals('inactive')
->getQuery()
->execute(['delete' => true]);
Index Utilization
explain() to analyze query performance:
$queryBuilder->getQuery()->explain();
Custom Hydrators
use Doctrine\ODM\MongoDB\Hydrator\HydratorInterface;
class CustomHydrator implements HydratorInterface
{
public function hydrate($document, $data)
{
// Custom logic
}
}
Event Subscribers
use Doctrine\ODM\MongoDB\Event\LifecycleEventArgs;
$dm->getEventManager()->addEventSubscriber(new class {
public function postLoad(LifecycleEventArgs $args)
{
// Post-load logic
}
});
Custom Repository
use Doctrine\ODM\MongoDB\Repository\DocumentRepository;
class UserRepository extends DocumentRepository
{
public function findByName($name)
{
return $this->createQueryBuilder()
->field('name')->equals($name)
->getQuery()
->execute();
}
}
Register in your document:
#[ODM\Repository(class: UserRepository::class)]
class User { ... }
Proxy Directory
proxy_dir manually; use the default (/runtime/Proxy).Connection Pooling
config/doctrine-mongodb-odm.php:
'connection' => [
'server' => [
'type' => 'mongodb',
'host' => 'localhost',
'port' => 27017,
'options' => [
'connect' => true,
'pool' => [
'min_size' => 1,
'max_size' => 10,
],
],
],
],
Read Preference
How can I help you explore Laravel packages today?