Laravel 10中whereHas无法过滤不符合条件的关联模型问题
Laravel 10 筛选关联模型并过滤嵌套关联的正确写法
你的问题核心是:仅用针对最内层关联的过滤条件,只会筛选出符合条件的Buyer,但不会自动过滤掉关联数据里不符合要求的tiers。要同时实现「只返回存在符合条件关联的Buyer」和「仅加载符合条件的tiers与options」,需要逐层嵌套过滤关联数据。
正确实现代码
可以用嵌套的withWhereHas来简洁实现需求:
$buyers = Buyer::withWhereHas('tiers', function ($tierQuery) { $tierQuery->withWhereHas('options', function ($optionQuery) { $optionQuery->where('type', 'private'); }); })->get();
如果想要更直观的分步写法,逻辑完全一致:
$buyers = Buyer::with(['tiers' => function ($tierQuery) { // 第一步:只加载包含符合条件options的tiers $tierQuery->whereHas('options', fn($q) => $q->where('type', 'private')) // 第二步:给选中的tiers,只加载type为private的options ->with(['options' => fn($q) => $q->where('type', 'private')]); }]) // 确保最终返回的Buyer至少有一组符合条件的tiers.options ->whereHas('tiers.options', fn($q) => $q->where('type', 'private')) ->get();
之前写法无效的原因
- 单独使用
with('tiers.options', function($q) { ... }):只会过滤最内层的options,但不会过滤tiers——那些没有符合条件options的tiers依然会被加载,只是它们的options集合为空。 - 直接使用
withWhereHas('tiers.options', ...):这个方法等价于with('tiers.options') + whereHas('tiers.options'),仅能确保Buyer本身符合条件,但加载的tiers还是全部数据,只是options被过滤了。
只有逐层嵌套过滤,先筛选出有符合条件options的tiers,再过滤该tiers下的options,才能得到你想要的结果:返回的Buyer关联数据中,没有空options的tiers,所有tiers都包含至少一个type为private的options。
内容的提问来源于stack exchange,提问作者Ryan H
相关产品推荐
相关产品推荐

