Laravel中如何基于关联模型的最新实例筛选主模型?
Laravel中如何基于关联模型的最新实例筛选主模型?
嘿,这个需求我之前做项目时刚好碰到过!要基于关联模型的最新记录筛选主模型,而且得用查询构造器保证大数据量下的性能,确实得找对方法。下面给你几种实用的方案,你可以根据自己的Laravel版本和业务场景选:
1. 最简洁的方案:利用Laravel的latestOfMany()关联(Laravel 8+适用)
首先在你的Product模型里定义一个关联,专门指向最新的状态记录:
// app/Models/Product.php public function latestStatus() { // latestOfMany()会自动获取该产品的最新ProductStatus实例 return $this->hasOne(ProductStatus::class)->latestOfMany(); }
之后直接用whereHas基于这个关联筛选就行,代码非常清爽:
$approvedProducts = Product::whereHas('latestStatus', function ($query) { $query->where('status', 'Approved'); })->get();
这个方法底层是Laravel帮你生成高效的子查询,既简洁又能保证性能,强烈推荐用这个!
2. 子查询+关联筛选(兼容低版本Laravel)
如果你用的是Laravel 8以下的版本,或者不想额外定义关联,可以直接用子查询来实现:
$approvedProducts = Product::whereHas('statuses', function ($query) { // 先获取当前产品的最新状态的创建时间(如果用自增id判断新旧,换成MAX(id)就行) $latestStatusTime = ProductStatus::select(DB::raw('MAX(created_at)')) ->whereColumn('product_id', 'products.id'); $query->where('status', 'Approved') // 确保这条状态是该产品的最新记录 ->where('created_at', $latestStatusTime); })->get();
这里的核心是用子查询拿到每个产品的最新状态时间,然后在whereHas里同时匹配状态值和“是否为最新记录”两个条件。
3. JOIN结合子查询(极致性能优化)
如果你的数据量特别大,JOIN的方式可能比子查询更高效(取决于数据库引擎和索引),可以这么写:
// 先获取每个产品对应的最新状态ID $latestStatusIds = ProductStatus::select('product_id', DB::raw('MAX(id) as latest_status_id')) ->groupBy('product_id'); $approvedProducts = Product::joinSub($latestStatusIds, 'latest_statuses', function ($join) { $join->on('products.id', '=', 'latest_statuses.product_id'); }) ->join('product_statuses', 'product_statuses.id', '=', 'latest_statuses.latest_status_id') ->where('product_statuses.status', 'Approved') ->select('products.*') // 只选择产品表的字段,避免字段冲突 ->get();
这种方式通过两次JOIN直接关联到最新的状态记录,筛选逻辑更直观,适合超大数据量的场景。
额外提示
不管用哪种方法,都建议给product_statuses表的product_id、status、created_at(或id)字段加上组合索引,能大幅提升查询速度!
备注:内容来源于stack exchange,提问作者Melly
相关产品推荐
相关产品推荐

