Laravel关联预加载中如何使用ids?仅返回单条帖子问题求助
解决Laravel关联预加载仅返回单条帖子的问题
首先得明确你当前代码的核心问题:当你用groupBy('industryIndex')对WsStock进行分组后,查询结果里的每一行其实是行业分组的聚合数据,而不是单个的WsStock模型实例。这时候你用with('posts')预加载关联时,Laravel会默认使用当前行的id(也就是分组后取到的第一个WsStock的id)去查询关联帖子,自然只能拿到对应这个单条WsStock的帖子,而不是GROUP_CONCAT出来的所有ids对应的帖子。
下面给你两种可行的解决方案:
方案一:手动关联分组后的所有帖子
这种方式保留你原来的分组聚合逻辑,然后手动查询所有相关帖子并关联到对应分组:
// 第一步:获取分组后的行业聚合数据 $stocks = WsStock::select([ 'industryIndex', 'nameFA', DB::raw('count(industryIndex) as total'), DB::raw('GROUP_CONCAT(id SEPARATOR ",") as ids') ]) ->whereHas('posts', function ($query) use ($userId) { $query->whereUserId($userId)->whereNotNull('ppa'); }) ->groupBy('industryIndex') ->get(); // 第二步:提取所有分组里的stock id,去重后查询符合条件的所有帖子 $allStockIds = collect($stocks->pluck('ids')) ->flatMap(fn($ids) => explode(',', $ids)) ->unique() ->toArray(); $posts = Post::whereIn('stock_id', $allStockIds) ->whereUserId($userId) ->whereNotNull('ppa') ->get() ->groupBy('stock_id'); // 按stock_id分组,方便后续关联 // 第三步:把帖子手动关联到对应的行业分组上 $stocks->each(function ($stock) use ($posts) { $stockIds = explode(',', $stock->ids); // 收集当前分组所有stock对应的帖子 $stockPosts = collect(); foreach ($stockIds as $id) { if ($posts->has($id)) { $stockPosts = $stockPosts->merge($posts->get($id)); } } // 给分组模型添加posts属性 $stock->setAttribute('posts', $stockPosts); });
方案二:先获取所有符合条件的模型再分组(如果不需要聚合字段)
如果你不需要total和ids这些聚合字段,只是想按行业分组展示对应的WsStock和它们的帖子,可以换个思路:
// 先获取所有符合条件的WsStock,并预加载对应的posts $stocks = WsStock::with(['posts' => function ($query) use ($userId) { $query->whereUserId($userId)->whereNotNull('ppa'); }, 'indice']) ->whereHas('posts', function ($query) use ($userId) { $query->whereUserId($userId)->whereNotNull('ppa'); }) ->get(); // 然后按industryIndex分组 $groupedStocks = $stocks->groupBy('industryIndex');
这种方式的好处是Laravel会正常处理预加载关联,每个WsStock都会带上自己的所有符合条件的帖子,最后再用集合的groupBy方法完成行业分组。
关键提示
- 避免在数据库层面分组后直接用Eloquent关联,因为分组后的结果已经不是标准的Eloquent模型,关联查询会失效;
- 集合的
groupBy和数据库的GROUP BY是完全不同的概念,前者是在内存中对查询结果进行分组,不会改变原始模型数据。
内容的提问来源于stack exchange,提问作者Mohammad
相关产品推荐
相关产品推荐

