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

Laravel WhereHas关联查询如何移除嵌套的多余子关联数据

需求与问题说明
  • 业务目标:按浏览量倒序输出推荐优惠信息,列表同步展示对应商家的logo、名称,支持按用户选择的城市、分类做筛选查询
  • 模型关系:Discount(优惠)模型从属关联Business(商家)模型
  • 现存问题:接口返回的优惠数据已挂载关联商家信息,但商家信息内部嵌套返回了该商家下所有优惠数据,属于冗余内容
  • 现有业务代码:
public function recommendations(Request $request)
{
    $fields = $request->validate([
        'categories' => 'array',
        'cities' => 'array'
    ]);

    $query = Discount::whereHas('business', function($innerQuery) use ($fields) {
        if ($fields['cities']) {
            $innerQuery->whereJsonContains('cities', $fields['cities'])
                ->orWhereNull('cities');
        }
        if ($fields['categories']) {
            $innerQuery->whereJsonContains('categories', $fields['categories'])
                ->orWhereNull('categories');
        }

    })
    ->with('business:id,logo')
    ->orderBy('views','desc');
    
    return $query->paginate(18);
}
  • 核心诉求:移除商家信息下嵌套的多余优惠关联数据
解决方法

冗余嵌套数据出现的原因是Business模型中默认开启了discounts关联的自动加载(通常是模型$with属性配置了全局预加载,或者关联方法里带了自动加载逻辑),两种处理方案可选:

方案1:预加载时单独禁用冗余关联(推荐,不影响其他接口逻辑)

预加载business关联时通过闭包指定返回字段,同时显式禁用不需要的discounts关联,另外当前预加载商家字段漏了需要展示的name字段,顺手修复了多筛选条件下or逻辑导致的查询条件失效问题,修正后代码如下:

public function recommendations(Request $request)
{
    $fields = $request->validate([
        'categories' => 'array',
        'cities' => 'array'
    ]);

    $query = Discount::whereHas('business', function($innerQuery) use ($fields) {
        if (!empty($fields['cities'])) {
            $innerQuery->where(function($q) use ($fields) {
                $q->whereJsonContains('cities', $fields['cities'])
                    ->orWhereNull('cities');
            });
        }
        if (!empty($fields['categories'])) {
            $innerQuery->where(function($q) use ($fields) {
                $q->whereJsonContains('categories', $fields['categories'])
                    ->orWhereNull('categories');
            });
        }
    })
    ->with(['business' => function($q) {
        $q->select('id', 'logo', 'name') // 按需选择需要返回的商家字段
            ->without('discounts'); // 核心:禁用商家模型下自动加载的优惠关联
    }])
    ->orderBy('views', 'desc');
    
    return $query->paginate(18);
}

注意:原代码中多个筛选条件直接拼接orWhereNull会打破条件的且逻辑,比如传了分类和城市筛选时,可能匹配到城市为空但分类不匹配的数据,上面代码给每个维度的筛选包了一层闭包,保证同维度的or条件不影响其他筛选规则。

方案2:移除模型全局自动加载配置

如果Business模型的$with属性中配置了discounts全局预加载,直接将该配置项移除即可。但这种修改会影响所有查询Business模型的接口,如果其他业务场景确实需要自动加载商家下的优惠数据,优先选择方案1。

内容的提问来源于stack exchange,提问作者guyhguy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 03:09:42