在 Laravel 项目开发中,我们经常会从数据库查询出包含多层关联信息的数据集,比如商品数据同时包含一级分类和二级分类字段,这两个字段都不是唯一的,需要将数据先按一级分类分组,再在每个一级分类下按二级分类二次分组,也就是实现二维分组的效果。

基础场景说明
假设我们有一个商品表 goods,表结构包含以下字段:id、name、first_category、second_category、price,其中 first_category 和 second_category 都是非唯一的字符串类型字段,我们需要查询所有商品,然后按这两个字段做二维分组,最终得到类似如下的结构:
[
"数码产品" => [
"手机" => [
["id" => 1, "name" => "某品牌手机", "price" => 2999],
["id" => 2, "name" => "另一品牌手机", "price" => 3999]
],
"耳机" => [
["id" => 3, "name" => "无线耳机", "price" => 599]
]
],
"家居用品" => [
"厨具" => [
["id" => 4, "name" => "炒锅", "price" => 199]
]
]
]
使用集合嵌套 groupBy 实现
Laravel 的 Eloquent 查询结果返回的是集合对象,集合自带的 groupBy 方法支持传入回调函数或者多个分组字段,我们可以通过嵌套调用 groupBy 来实现二维分组。
步骤1:查询原始数据
首先我们通过模型查询出需要的商品数据,这里不需要在数据库层面做分组,直接获取全部需要的字段即可:
<?php
namespace AppHttpControllers;
use AppModelsGoods;
use IlluminateHttpRequest;
class GoodsController extends Controller
{
public function getGroupedGoods()
{
// 查询所有商品,只获取需要的字段
$goodsList = Goods::select('id', 'name', 'first_category', 'second_category', 'price')
->get();
// 后续分组逻辑
}
}
步骤2:执行二维分组
集合的 groupBy 方法如果传入多个字段名,会依次按照字段进行分组,刚好满足我们的二维分组需求,直接在查询结果上调用即可:
// 接上面的代码 $groupedGoods = $goodsList->groupBy(['first_category', 'second_category']); // 如果需要转为数组方便后续处理,可以调用 toArray 方法 $groupedArray = $groupedGoods->toArray(); return response()->json($groupedArray);
这里 groupBy 传入的数组第一个元素是第一次分组的字段,第二个是第二次分组的字段,集合会自动先按 first_category 分组,再在每个分组内按 second_category 分组,完全符合非唯一字段二维分组的需求。
自定义分组逻辑处理特殊情况
如果分组字段存在空值,或者需要对分组字段做额外的处理(比如统一转为小写、去除空格),可以在 groupBy 中传入回调函数自定义分组规则。
处理分组字段空值的场景
如果部分商品的 second_category 字段为空,我们希望将这些空值的商品归到名为“未分类”的分组下,可以这样实现:
$groupedGoods = $goodsList->groupBy(function ($item) {
// 一级分组:处理 first_category 空值
return $item->first_category ?: '未分类';
})->map(function ($firstGroup) {
// 二级分组:处理 second_category 空值
return $firstGroup->groupBy(function ($item) {
return $item->second_category ?: '未分类';
});
});
$groupedArray = $groupedGoods->toArray();
这里先通过回调函数定义一级分组的规则,对一级分组后的每个子集合再调用 groupBy 定义二级分组规则,灵活性更高,可以适配各种复杂的分组场景。
注意事项
- 数据库查询时不要在 SQL 层面使用
GROUP BY,因为 SQL 的GROUP BY会合并相同字段的行,导致非唯一字段的其他数据丢失,二维分组应该在获取到查询结果后通过集合操作实现。 - 如果数据量非常大,集合操作会占用较多内存,建议在查询时通过
chunk方法分块处理,避免内存溢出。 - 分组后的集合如果还需要做其他处理,比如排序、过滤,可以在分组前后调用集合的其他方法,比如
sortBy、filter等,集合方法支持链式调用。
总结
在 Laravel 中按非唯一字段实现二维分组,核心是利用集合的 groupBy 方法,既可以直接传入多个字段名快速实现,也可以通过回调函数自定义分组规则处理特殊场景。这种方式不需要修改数据库查询逻辑,在应用层处理分组逻辑也更加灵活,能够满足大部分开发中的二维分组需求。
Laravelcollection_groupBy非唯一字段分组二维数组分组eloquent查询修改时间:2026-07-23 11:06:31