如何在MongoDB与Laravel/Eloquent中获取EmbedsMany关系的反向关联
Laravel-MongoDB 5.x 嵌入式关系反向关联实现方案
你说得没错,Mongo官方接手维护Laravel-MongoDB 5.x版本后,确实移除了4.x中自动生成的嵌入式关系反向关联功能(即直接通过$book->user获取父模型)。官方调整的原因是嵌入式文档本质是父文档的一部分,MongoDB原生设计中并没有给嵌入式文档自动存储父引用的机制,4.x的自动关联是包的额外封装,5.x版本更贴近MongoDB原生逻辑。
下面提供几种可行的替代实现方式:
1. 手动存储父模型引用(推荐)
在嵌入式模型中添加字段存储父模型的ID和类型,保存时手动赋值,再通过关联方法获取父模型,这是性能最稳定的方案。
代码示例:
// Book模型 class Book extends Model { protected $fillable = ['title', 'user_id', 'user_type']; // 定义反向关联 public function user() { return $this->belongsTo($this->user_type, 'user_id'); } }
保存嵌入式文档时手动设置父引用:
$user = User::first(); $book = new Book(['title' => 'MongoDB实战']); // 存储父模型ID和类名 $book->user_id = $user->_id; $book->user_type = User::class; $user->books()->save($book);
之后就可以像4.x版本一样调用:
$book = Book::first(); $user = $book->user;
2. 通过查询父模型集合获取(无额外字段)
如果不想新增字段,可以直接查询父模型集合,找到包含当前嵌入式文档的记录。注意:数据量大时需要给books._id添加索引来提升性能。
代码示例:
// Book模型中自定义访问器 class Book extends Model { public function getUserAttribute() { return User::where('books._id', $this->_id)->first(); } }
调用方式不变:
$book = Book::first(); $user = $book->user;
3. 使用MongoDB聚合查询(复杂场景)
对于需要筛选、投影的复杂场景,可以用MongoDB聚合管道实现:
// Book模型中自定义访问器 class Book extends Model { public function getUserAttribute() { $pipeline = [ ['$unwind' => '$books'], ['$match' => ['books._id' => $this->_id]], ['$project' => ['_id' => 1, 'name' => 1]] // 只返回需要的字段 ]; return User::raw()->aggregate($pipeline)->current(); } }
内容的提问来源于stack exchange,提问作者cfkane
相关产品推荐
相关产品推荐

