Laravel 5.5中如何对Api Resources的JSON响应进行分组?
在Laravel 5.5中对API Resources返回的JSON按年/月分组
我来一步步帮你实现按年月分组并格式化API响应的需求:
1. 先处理数据库查询(合并同年月的人员数据)
首先要从数据库层面把相同年份和月份的人员数据合并,还要去掉重复的名字(比如你例子里的「中島 春香」出现了两次)。假设你的模型是PeopleRecord,对应数据表为people_records,可以这么写查询:
use Illuminate\Support\Facades\DB; $records = DB::table('people_records') ->select( 'year', 'month', DB::raw('GROUP_CONCAT(DISTINCT people SEPARATOR ", ") as merged_people') ) ->groupBy('year', 'month') ->orderBy('year', 'desc') ->orderBy('month', 'desc') ->get();
这里用GROUP_CONCAT(DISTINCT ...)完成人员名字的合并与去重,同时按年月降序排列,让最新的数据排在前面。
2. 创建API资源类
接下来创建资源类来格式化单条记录,先执行命令生成资源:
php artisan make:resource PeopleRecordResource
然后修改app/Http/Resources/PeopleRecordResource.php的toArray方法,把合并后的字符串转成数组(更符合API的规范格式):
<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Json\JsonResource; class PeopleRecordResource extends JsonResource { public function toArray($request) { return [ 'year' => $this->year, 'month' => $this->month, 'people' => explode(', ', $this->merged_people) ]; } }
如果需要进一步按年份嵌套分组(把同一年的所有月份数据放在一起),可以再创建一个集合资源类YearGroupedPeopleResource:
<?php namespace App\Http\Resources; use Illuminate\Http\Resources\Json\ResourceCollection; class YearGroupedPeopleResource extends ResourceCollection { public function toArray($request) { // 先按年份分组 $grouped = $this->collection->groupBy('year'); // 格式化每个年份下的月份数据 return $grouped->map(function ($monthRecords, $year) { return [ 'year' => $year, 'months' => PeopleRecordResource::collection($monthRecords) ]; })->values()->all(); } }
3. 在控制器中返回分组后的响应
根据你的需求选择不同的返回方式:
选项1:仅按年月平级分组
use App\Http\Resources\PeopleRecordResource; public function index() { $records = DB::table('people_records') ->select( 'year', 'month', DB::raw('GROUP_CONCAT(DISTINCT people SEPARATOR ", ") as merged_people') ) ->groupBy('year', 'month') ->orderBy('year', 'desc') ->orderBy('month', 'desc') ->get(); return PeopleRecordResource::collection($records); }
返回的JSON格式示例:
[ { "year": 2017, "month": 11, "people": ["..."] }, { "year": 2017, "month": 3, "people": ["松本 知実", "桐山 裕太", "吉本 稔", "藤本 稔"] }, // 其他记录 ]
选项2:按年份嵌套分组
use App\Http\Resources\YearGroupedPeopleResource; public function index() { $records = DB::table('people_records') ->select( 'year', 'month', DB::raw('GROUP_CONCAT(DISTINCT people SEPARATOR ", ") as merged_people') ) ->groupBy('year', 'month') ->orderBy('year', 'desc') ->orderBy('month', 'desc') ->get(); return new YearGroupedPeopleResource($records); }
返回的JSON格式示例:
[ { "year": 2017, "months": [ { "year": 2017, "month": 11, "people": ["..."] }, { "year": 2017, "month": 3, "people": ["松本 知実", "桐山 裕太", "吉本 稔", "藤本 稔"] } ] }, { "year": 2016, "months": [ { "year": 2016, "month": 12, "people": ["中島 春香", "中津川 充", "村山 裕樹", "杉山 翼", "木村 稔"] } ] }, // 其他年份 ]
小提示
- 如果你的
people字段原本就是逗号分隔的字符串,GROUP_CONCAT会自动合并后再用逗号分隔,DISTINCT参数能有效去掉重复的名字。 - 以上写法完全适配Laravel 5.5版本的API Resources特性,不需要额外扩展。
内容的提问来源于stack exchange,提问作者Ryutaro Matsumoto
相关产品推荐
相关产品推荐

