【问题标题】:Laravel 5 - multi-dimensional groupBy, orderBy & paginateLaravel 5 - 多维 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, ForestBB for user-2, Dance 等返回EE。结合相同的user_ids 和相同的主题。但相反,它为user-3, Forest返回CC
  • 交换orderBygroupBy的位置:Post::wher('verified', '1')->groupBy('topic', 'publisher_id')->orderBy('created_at', 'desc')->paginate(5)

标签: php ajax laravel pagination


【解决方案1】:

删除了我之前的回答,但仍会包含来自 Laravel Pagination 的关于将 groupBy()paginate() 链接起来的注释。

注意:目前,使用 groupBy 语句的分页操作不能被 Laravel 高效执行。如果您需要使用groupBy 与分页结果集,建议您查询数据库并手动创建分页器。

更新

由于created_at 字段的日期格式不寻常,您需要整数casted 值才能被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 { }
猜你喜欢
  • 2016-01-22
  • 1970-01-01
  • 2016-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-29
  • 2015-05-07
  • 2015-08-06
相关资源
最近更新 更多