Laravel关联模型条件子查询:筛选最后一条关联记录符合条件的用户
你遇到的问题其实是对Laravel中with()方法的作用理解有偏差——with()是用来预加载关联数据的,它只会过滤关联的properties记录,不会对主模型User进行筛选,所以不管用户的properties是否符合条件,所有User都会被返回。
要实现「筛选出关联properties最后一条记录的unit_id/group_id/team_id等于指定$catId的用户」,你需要用whereHas配合子查询,或者通过join关联最新的properties记录来过滤主模型。下面给你两种可行的写法:
方法一:使用whereHas + 子查询定位最新关联记录
这种方法先通过子查询找到每个用户的最后一条properties记录,再判断这条记录是否满足条件:
$users = User::whereHas('properties', function ($query) use ($catId) { // 获取当前用户最新的properties记录ID $latestPropertySubquery = Property::select('id') ->whereColumn('user_id', 'users.id') ->latest() // 按时间戳排序取最新,也可以用orderBy('id', 'desc') ->limit(1); // 筛选出最新记录符合条件的用户 $query->whereIn('id', $latestPropertySubquery) ->where(function ($q) use ($catId) { // 把orWhere包裹在闭包里,避免逻辑优先级错误 $q->where('team_id', $catId) ->orWhere('group_id', $catId) ->orWhere('unit_id', $catId); }); })->get();
方法二:通过Join关联最新的properties记录
如果你的properties表有自增ID或者明确的时间戳字段,也可以用join的方式直接关联最新记录:
$users = User::join('properties as latest_p', function ($join) { $join->on('latest_p.user_id', '=', 'users.id') // 子查询确保关联的是当前用户的最后一条记录 ->whereRaw('latest_p.id = (SELECT MAX(id) FROM properties WHERE user_id = users.id)'); })->where(function ($q) use ($catId) { $q->where('latest_p.team_id', $catId) ->orWhere('latest_p.group_id', $catId) ->orWhere('latest_p.unit_id', $catId); })->select('users.*') // 只选择User表的字段,避免关联表字段干扰 ->distinct() // 确保每个用户只返回一次 ->get();
为什么你之前的写法不对?
- 第一种写法:
with('properties', function($query) { ... })只会过滤加载的properties数据,但不会排除那些没有符合条件properties的User,所以所有User都会被返回,只是部分用户的properties关联是空的。 - 第二种写法加了
latest(),也只是加载每个用户最新且符合条件的properties,但同样不会过滤主模型User,不符合条件的User依然会被返回,只是他们的properties关联为空。
如果你的「最新记录」是按created_at或updated_at排序,记得把代码里的MAX(id)或者latest()换成对应的字段,比如orderBy('updated_at', 'desc')。
内容的提问来源于stack exchange,提问作者fefe
相关产品推荐
相关产品推荐

