You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 10:12:59