Laravel 5 - 多维 groupBy、orderBy 和 paginate
Posted
技术标签:
【中文标题】Laravel 5 - 多维 groupBy、orderBy 和 paginate【英文标题】:Laravel 5 - multi-dimensional groupBy, orderBy & paginate 【发布时间】:2016-01-21 04:22:34 【问题描述】:我有一个 Post 模型,我正在尝试 ->paginate()
、->groupBy()
和 ->orderBy()
。
public function index()
$posts = Post::where('verified', '1')
->orderBy('created_at','desc')
->groupBy('topic', 'publisher_id')
->paginate(5);
// dd($posts);
同时,数据库中的数据如下所示:
| id | verified | topic | publisher_id | body | created_at |
| 25 | 1 | Forest | 3 | EE | 10.12.50 |
| 24 | 1 | Forest | 3 | DD | 10.11.40 |
| 23 | 1 | Forest | 3 | CC | 10.10.30 |
| 22 | 1 | Dance | 2 | BB | 9.50.50 |
| 21 | 1 | Dance | 2 | AA | 9.40.40 |
| 20 | 1 | Music | 1 | ZZ | 9.30.30 |
| 19 | 1 | Music | 1 | XX | 9.20.20 |
| 18 | 1 | Art | 1 | YY | 9.10.10 |
| 17 | 1 | Art | 1 | WW | 9.00.00 |
| 16 | 1 | Ski | 2 | KK | 7.00.00 |
当我取消注释 dd()
并运行代码时,我得到这个日志:
LengthAwarePaginator
...
items :
items :
0 => Post..
1 => Post..
2 => Post..
3 => Post..
...
...
0 => Post#249 : "published_by: "3", "body": "CC", "created_at": "10.10.30"
1 => Post#250 : "published_by: "1", "body": "XX", "created_at": "9.20.20"
2 => Post#251 : "published_by: "1", "body": "WW", "created_at": "9.00.00"
3 => Post#252 : "published_by: "2", "body": "KK", "created_at": "7.00.00"
它看起来很奇怪是有原因的。它为用户 3 提供了groupBy
,但对其他人却没有。此外,它正在拉动最早创建的而不是最晚创建的。将desc
更改为asc
(如->orderBy('created_at', 'asc')
)会使一切完全偏离轨道。
换句话说,返回 'CC' for user-3, Forest
而不是 'EE' for user-3, Forest
然后我想可能是 ->paginate(5)
搞砸了。
public function post()
$posts = Post::where...
...
->paginate(5);
$postsTry = Post::where('verified', '1')
->orderBy('created_at','desc')
->groupBy('topic', 'publisher_id')
->get();
// dd($postsTry);
我得到一个集合,其中只有 items
像上面的对象。
(0 => Post.., 1 => Post.., 2 => Post..
)。
它将数据分组为最早的优先,而不是最新的优先。我错过了什么?我做错了什么?
总结一下,请注意我想要得到的是:
'EE' for user-3, Forest
'BB' for user-2, Dance
'ZZ' for user-1, Music
'YY' for user-1, Art
【问题讨论】:
你能把$posts->toSql();
的结果贴出来吗?
"select * from posts
where verified
= 1
group by topic
, publisher_id
order by created_at
desc"。当我在->paginate(5)->toSql();
之后尝试时,它会抛出一个错误,所以我在->groupBy()
之后添加了
GroupBy 按预期工作,它按publisher_id
AND topic
分组。由于 publisher_id 为 1 和 2 的记录涵盖多个主题,因此您最终会得到多个记录(存在的每个唯一主题的记录)。
那么,逻辑完全错误吗?我想做的只是为user-3, Forest
、BB for user-2, Dance
等返回EE
。结合相同的user_ids 和相同的主题。但相反,它为user-3, Forest
返回CC
交换orderBy
和groupBy
的位置:Post::wher('verified', '1')->groupBy('topic', 'publisher_id')->orderBy('created_at', 'desc')->paginate(5)
【参考方案1】:
删除了我之前的回答,但仍会包含来自 Laravel Pagination 的关于将 groupBy()
与 paginate()
链接起来的注释。
注意:目前,使用
groupBy
语句的分页操作不能被 Laravel 高效执行。如果您需要使用groupBy
与分页结果集,建议您查询数据库并手动创建分页器。
更新
由于created_at
字段的日期格式不寻常,您需要整数cast
ed 值才能被order by
语句正确使用(作为整数,而不是字符串)。这是一个工作示例:
Post::selectRaw("*, CAST(REPLACE(created_at, '.', '') AS UNSIGNED INTEGER) ca")
->where('verified', '1')
->orderBy('ca', 'desc')
->groupBy('topic', 'publisher_id')
->paginate();
【讨论】:
由于分页在运行查询时仅使用LIMIT ?,?
,因此它仍然有效。这不是高效,因为 SQL 必须在所有记录上运行 GROUP BY
才能限制结果。但在任何情况下都是如此,您只能添加条件来减少您的预组结果集以尝试和优化。这也不是他要处理的问题。他试图将每个匹配组的最新日期的行作为分组行。
@DavidBoskovic 感谢您指出这一点。我刚刚更新了我的答案。但无论如何,仍然不鼓励链接groupBy()
和paginate()
。
@SandyandiN.delaCruz 我尝试添加您的示例selectRaw("*, CAST(REPLACE(created_at, '.', '') AS UNSIGNED INTEGER) ca")
,但仍然得到相同的结果'CC' for user-3, Forest
。我一直在努力,但仍然无法弄清楚为什么。什么是(最有效的)方法?我怎样才能达到'EE' for user-3, Forest
、'BB' for user-2, Dance
等..?
你orderBy('ca', 'desc')
了吗?我用你拥有的数据进行了尝试,我得到了用户#3 的 EE。
首先,我忘记将created_at, 'desc'
更改为'ca'
,我在上一条评论中得到了结果。现在,我对其进行了编辑,但由于某种原因,作为[0] => Post
,我得到了第一个数据(id=1 id(auto increment)
)。 :S 为什么我的行为不同..?可能与分页中的数字有关(->paginate(#)
)?另外,我刚刚意识到我可以使用自动递增的id
而不是created_at
,这些仍然应该传递相同的数据,不是吗?但是,这也不起作用。【参考方案2】:
您需要使用子查询(或其他联接方法)来获取组中的顶部项目。见Getting The Rows Holding the Group-wise Maximum of a Certain Column
删除了我的例子。
【讨论】:
Call to a member function orderBy() on string
添加->addSelect(DB::raw('MAX(
created_at) as
created_at'))
会导致集合中仅选择并返回created_at
字段。 items items 0 => Post #1 attribute 1 => Post #1 attribute ...
试试->select('*',DB::raw('MAX(created_at) as created_at'))
现在,它正在选择所有内容,但使用相同的 created_at 顺序(最早在前)。
"select *, MAX(created_at) as created_at from posts
where verified
= 1
group by topic
, publisher_id
order by created_at
desc" 它仍然返回'CC' for 0 = > Post
以上是关于Laravel 5 - 多维 groupBy、orderBy 和 paginate的主要内容,如果未能解决你的问题,请参考以下文章
groupby 函数不适用于 laravel 5.5 中的二维数组
groupBy withCount 闭包(Laravel 5.3.26)