PHP操作MongoDB时ObjectId存储为带oid的对象导致$lookup失效如何解决
问题根因
这是PHP MongoDB驱动场景下的常见序列化问题,本质是写入文档前,MongoDB\BSON\ObjectId实例被提前转换为了普通stdClass对象:当BSON类型对象被执行JSON序列化、数组强转,或者经过未做BSON适配的ORM/封装层处理时,就会被拆解为包含oid键的普通对象,入库后就不会被识别为原生ObjectId类型。
解决方案
- 写入前验证字段类型:调用写入方法前,先确认对应字段是合法的ObjectId实例,可以用以下代码验证:
若返回false则说明字段在写入前已经被转换,需要排查上游逻辑。var_dump($ownership->_id instanceof MongoDB\BSON\ObjectId); - 避免无效序列化操作:不要在写入前对包含BSON类型的数据执行
json_decode(json_encode($对象))、(array)强转、get_object_vars这类操作,这类操作都会破坏BSON对象的原生结构。 - 适配ORM的类型声明:如果使用了Laravel MongoDB这类上层封装扩展,需要在对应模型的
$casts属性中声明字段类型为ObjectId,避免框架自动转换:protected $casts = [ '_id' => 'objectid', // 其他关联字段如果是ObjectId也需要同步声明 ]; - 修复已入库的错误数据:可以在Mongo Shell中执行批量更新,把存量的带
oid的字段转换为原生ObjectId,注意替换集合名:
字段修复完成后即可正常执行db.你的集合名.find({ "_id.oid": { $exists: true } }).forEach(doc => { db.你的集合名.updateOne( { _id: doc._id }, { $set: { _id: ObjectId(doc._id.oid) } } ) })$lookup关联查询。
内容的提问来源于stack exchange,提问作者Guilherme Sampaio
相关产品推荐
相关产品推荐

