Laravel集合过滤后转JSON结构异常问题咨询
这确实是预期行为,我来给你掰扯清楚原因和对应的解决办法:
为什么会出现这种情况?
当你用Laravel集合的->filter()方法时,集合会保留原查询结果的原始键名(也就是数据库记录在集合中的初始索引位置)。比如原集合是按created_at倒序取出的25条记录,它们的索引是从0到24。当你过滤掉前24条,只留下第25条时,过滤后的集合就只剩一个非连续索引的元素。
而PHP的json_encode()函数有个规则:如果数组的键是非连续的整数索引,就会把它编码成JSON对象而不是数组。Laravel的->toJson()底层就是调用这个函数,所以最终返回的就是{25: {"id": 25}}这种带键的对象结构,破坏了原本的数组格式。
至于为什么过滤前几项是正常的?因为如果过滤后的集合键是0、1、2这种连续的整数索引,json_encode()会识别为普通数组,自然就返回[{"id":1},...]的结构了。
解决办法:重置集合索引
只需要在filter()之后调用->values()方法,它会返回一个重新索引的新集合,键会从0开始连续排列,这样转JSON时就会保持数组结构:
$logs = RequestLog::orderBy('created_at', 'DESC')->whereBetween('created_at', [$start, $end])->get(); // 过滤后调用values()重置索引 $logs = $logs->filter(function($log) { /* 你的自定义过滤逻辑 */ })->values(); // 直接传集合给response()->json()即可,无需手动调用toJson() return response()->json($logs);
另外提个小优化:你原来写的return response()->json($logs->toJson());有点多余,response()->json()会自动把集合(或数组)转成JSON格式,直接传集合进去就好。
如果你习惯用普通数组处理,也可以先把集合转成数组,过滤后用array_values()重置索引,效果是一样的:
$logs = RequestLog::orderBy('created_at', 'DESC')->whereBetween('created_at', [$start, $end])->get()->toArray(); $logs = array_filter($logs, function($log) { /* 自定义逻辑 */ }); // 重置数组索引 $logs = array_values($logs); return response()->json($logs);
不过第一种用集合->values()的方式更符合Laravel的开发习惯,推荐优先使用。
内容的提问来源于stack exchange,提问作者TKoL

