应直接使用 Doctrine MongoDB ODM 而非原生 PHP 驱动,因 Symfony 官方仅支持 ODM 以保障生命周期管理、事件钩子和实体映射;需通过 composer 安装 doctrine/mongodb-odm-bundle 并在 bundles.php 中注册,DATABASE_URL 必须为 mongodb:// 协议,实体类须含 @ODM\Document 注解并声明 @ODM\Id 字段,查询必须经 DocumentRepository 执行。

直接用 Doctrine MongoDB ODM 连 MongoDB,别碰原生 PHP 驱动 —— Symfony 官方只认 ODM,硬上原生库会断掉生命周期管理、事件钩子和实体映射。
安装 doctrine/mongodb-odm-bundle 并注册 Bundle
ODM 不是 Symfony 内置组件,必须手动装包并启用。不注册 Bundle 会导致 doctrine_mongodb 服务不存在,后续所有配置都白搭。
- 运行
composer require doctrine/mongodb-odm-bundle(注意不是mongodb/mongodb) - 在
config/bundles.php中确认有Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle::class => ['all' => true] - 如果用的是 Symfony 6.4+,Bundle 会自动加载;但老项目或自定义 kernel 可能漏掉,得手写
DATABASE_URL 格式必须带 mongodb:// 协议头
.env 里写错协议头是最常见连不上原因 —— MySQL 的 mysql:// 和 MongoDB 的 mongodb:// 不能混用,ODM 不识别 mongodb+srv:// 除非你显式升级到 v4.5+ 并配 driverOptions。
- 本地开发用:
MONGODB_URL=mongodb://127.0.0.1:27017/myapp?connectTimeoutMS=5000 - Atlas 连接用:
MONGODB_URL=mongodb+srv://user:pass@cluster.mongodb.net/?retryWrites=true(仅限 ODM v4.5+) - 密码含
@或/必须 URL 编码,比如pa@ss/word→pa%40ss%2Fword - 别在
config/packages/doctrine_mongodb.yaml里硬编码 host/port —— 这样没法换环境,.env才是唯一真相源
实体类必须加 @Document 注解且指定 collection
ODM 不像 ORM 那样靠命名约定自动映射,@Document 是开关,漏了就等于没声明这个类是文档,php bin/console doctrine:mongodb:schema:create 会直接跳过它。
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
<p>/**</p><ul><li><p>@ODM\Document(collection="users")
*/
class User
{
/*<em> @ODM\Id </em>/
public $id;</p><p>/*<em> @ODM\Field(type="string") </em>/
public $name;
}-
@ODM\Document必须存在,collection参数推荐显式写,避免默认用类名小写(如User→user),容易和已有集合冲突 -
@ODM\Id字段不能省 —— ODM 要靠它生成_id,否则插入时抛Missing id field - 字段类型写
type="string"比留空更安全,ODM 对 null 类型推断不稳定,尤其嵌套数组或对象时
查询必须走 DocumentRepository,不能用 getConnection()
ODM 没有 getConnection() 这种裸连接入口 —— 它的查询全走 Repository 层,硬调原生驱动会绕过变更跟踪、UoW 和事件监听,导致 prePersist 等钩子失效。
- 正确方式:
$repo = $this->get('doctrine_mongodb')->getManager()->getRepository(User::class); $user = $repo->findOneBy(['name' => 'Alice']); - QueryBuilder 用法:
$qb = $repo->createQueryBuilder()->field('age')->gt(18)->sort('createdAt', -1); - 地理查询必须先建
2dsphere索引:@ODM\Index(keys={"location"="2dsphere"}),否则$qb->field('location')->near($lat, $lng)直接报错 - 别在控制器里 new EntityManager() —— 容器管理的
doctrine_mongodb.odm.document_manager才带事务和缓存上下文
ODM 的坑不在连接本身,而在“你以为它像 ORM 一样工作”的那一瞬间 —— 实体注解、索引声明、Repository 路径、甚至错误提示里的 DocumentManager 和 EntityManager 名字差一个词,但行为完全不同。


















