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

Laravel Eloquent查询问题:获取带main标签或首图的媒体数据

解决Eloquent关联查询优先返回指定标签媒体的问题

方案一:数据库层面直接筛选(推荐)

通过在关联查询中排序+限制,让数据库直接返回每个模型的优先媒体,性能最优:

$models = Model::with(['media' => function ($query) {
    // 按是否包含'main'标签降序排序,带标签的排在最前
    $query->orderByRaw("JSON_CONTAINS(custom_properties->'$.tags', '\"main\"') DESC")
          // 按媒体ID升序确保无标签时取关联的第一个媒体
          ->orderBy('id', 'asc')
          // 只返回符合要求的第一条媒体
          ->limit(1);
}])->paginate(self::PER_PAGE);

return $models;

原理说明

  • JSON_CONTAINS(custom_properties->'$.tags', '\"main\"') 返回1(包含标签)或0(不包含),降序排序后带'main'的媒体会排在同模型媒体的最前面
  • 再按id升序保证无标签时取关联的第一个媒体
  • limit(1)确保每个模型仅返回一条符合要求的媒体

方案二:分页后补充缺失数据(保持原分页结构)

如果需要保留原关联查询逻辑,可先分页获取带'main'标签的媒体,再批量补充无标签模型的第一个媒体,避免N+1查询:

// 第一步:获取带'main'标签媒体的分页模型
$models = Model::with(['media' => function ($query) {
    $query->whereJsonContains('custom_properties->tags', 'main');
}])->paginate(self::PER_PAGE);

// 收集没有媒体的模型ID
$missingMediaModelIds = $models->items()
    ->filter(fn($model) => $model->media->isEmpty())
    ->pluck('id');

if ($missingMediaModelIds->isNotEmpty()) {
    // 批量获取这些模型的第一个媒体,按模型ID分组
    $fallbackMedia = Media::whereIn('model_id', $missingMediaModelIds)
        ->orderBy('model_id')
        ->orderBy('id')
        ->get()
        ->groupBy('model_id');

    // 给对应模型设置 fallback 媒体
    $models->items()->each(function ($model) use ($fallbackMedia) {
        if ($model->media->isEmpty() && isset($fallbackMedia[$model->id])) {
            $model->setRelation('media', collect([$fallbackMedia[$model->id]->first()]));
        }
    });
}

return $models;

注意事项

  • 使用setRelation()方法修改模型关联数据,不会破坏原LengthAwarePaginator实例结构
  • 批量查询 fallback 媒体,避免循环查询带来的性能问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 09:25:44