Laravel 按分页排序

Posted

技术标签:

【中文标题】Laravel 按分页排序【英文标题】:Laravel sortBy paginate 【发布时间】:2014-12-10 13:27:50 【问题描述】:

我有一个 posts 表和 cmets 表,comment 属于 post,并且我在 Post 和 Comment 模型中有关系设置。我确实按照每个帖子的 cmets 数量对帖子进行了排序,如下所示:

      $posts = Post::with('comments')->get()->sortBy(function($post) 
           return $post->comments->count();
      );

我想知道如何对这些排序的帖子进行分页?

      $posts = Post::with('comments')->get()->sortBy(function($post) 
           return $post->comments->count();
      )->paginate(20);

不起作用并给我一个错误,说 paginate 是一个未定义的方法。

【问题讨论】:

【参考方案1】:

我不知道你是否可以使用 Eloquent 来做到这一点,但你可以使用 join 来做到这一点:

$posts = Post::leftJoin('comments','posts.id','=','comments.post_id')->
               selectRaw('posts.*, count(comments.post_id) AS `count`')->
               groupBy('posts.id')->
               orderBy('count','DESC')->
               paginate(20);

但是,在这种情况下,似乎所有记录都是从数据库中获取的,并且只显示来自分页器的记录,所以如果您有很多记录,那就是资源浪费。看来您应该为此进行手动分页:

$posts = Post::leftJoin('comments','posts.id','=','comments.post_id')->
               selectRaw('posts.*, count(comments.post_id) AS `count`')->
               groupBy('posts.id')->
               orderBy('count','DESC')->
               skip(0)->take(20)->get();

使用 skiptake 但我不是 Eloquent 专家,也许有更好的解决方案可以实现您的目标,所以您可以等待,也许有人会给出更好的答案。

【讨论】:

谢谢,所以要明确一点,这个解决方案不会从数据库中获取所有记录然后对其进行排序,它一开始只获取20条记录对吗? @dulan,是的,如果我们谈论的是第二个代码。在第一个代码中,所有记录都将从数据库中获取并仅显示其中一些记录,因此您需要选择第二个解决方案【参考方案2】:

这听起来很明显,但 Eloquent 不会在这里返回结果集,而是会返回一个集合。

如果你深入研究源码(Builder::get调用Builder::getFresh,调用Builder::runSelect,调用Connection::select),你会发现它的意图是简单地返回结果,然后将结果放入一个集合(具有 sortBy 方法)。

/**
 * Run a select statement against the database.
 *
 * @param  string  $query
 * @param  array  $bindings
 * @param  bool  $useReadPdo
 * @return array
 */
public function select($query, $bindings = array(), $useReadPdo = true)

  return $this->run($query, $bindings, function($me, $query, $bindings) use ($useReadPdo)
      
    if ($me->pretending()) return array();

    // For select statements, we'll simply execute the query and return an array
    // of the database result set. Each element in the array will be a single
    // row from the database table, and will either be an array or objects.
    $statement = $this->getPdoForSelect($useReadPdo)->prepare($query);

    $statement->execute($me->prepareBindings($bindings));

    //** this is a very basic form of fetching, it is limited to the PDO consts.
    return $statement->fetchAll($me->getFetchMode());
  );  

如果你想在不加载每个项目的情况下进行分页,那么你需要使用@Marcin的解决方案(复制如下):

$posts = Post::leftJoin('comments','posts.id','=','comments.post_id')->
           selectRaw('posts.*, count(comments.post_id) AS `count`')->
           groupBy('posts.id')->
           orderBy('count','DESC')->
           skip(0)->take(20)->get();

【讨论】:

【参考方案3】:

只需删除链式调用中的get(),看看你得到了什么,paginate 应该替换 get() 调用。

【讨论】:

这行不通。 sortBy 用于结果集,因此使用 paginate 使得仅对前 20 行而不是所有记录进行排序。这就是区别。先排序再分页不相反 我建议他把get()去掉,不要用paginate()代替,paginate从功能上来说会代替。

以上是关于Laravel 按分页排序的主要内容,如果未能解决你的问题,请参考以下文章

在 Laravel 中对分页变量进行排序

Laravel(三)分页排序和过滤

laravel分页和排序表

Eloquent Laravel 按相关模型排序分页查询

Laravel Eloquent 按孩子的长度排序,然后分页

Laravel orderBy 与分页和关系