簡體   English   中英

Eloquent ORM分頁Reddit-like - 在hash-id之前/之后

[英]Eloquent ORM pagination Reddit-like - before/after hash-id

我有一個排名列的帖子表。 有沒有辦法從一個帖子的ID開始檢索前20個帖子,同時按排名排序。 它的行為與reddit的分頁相似。

防爆。 domain.com/posts/previous/{id_of_post_to_start_from}

UPDATE

讓我重新說一下。 正常的laravel / eloquent(簡單)分頁將使用頁面,可以通過執行以下操作來實現:

$posts = Post::with(array('user'=>function($q){
            $q->select('id', 'img','nick', 'points', 'slug');
        }))
           ->with('categories')
           ->with('voted')
           ->orderBy('rank', 'DESC')
           ->orderBy('created_at','DESC')
           ->simplePaginate(20);
return view('layouts.home')->with('posts',$posts);

這將使用帶有?page=pageNo參數的url。 因為排名變化非常快,我真正想要的是能夠在id或hashId標識的某個帖子之后獲得以下或之前的帖子。 這是reddit的方式:

https://www.reddit.com/?count=25&after=t3_4g1n0n

更新2

@jarek的答案似乎在按排名欄排序時起作用,因為它很少或沒有重復,但在按投票數排序時失敗。 它只顯示3頁而不是5頁,在最后一頁中會跳過一些行。 我一直試圖解決這個問題一整天,我真的不知道下一步該去哪里。 請幫忙。

我的網址是/ordered-by-votes?before=hashId/ordered-by-votes?after=hashId

按結構votes desc, created_at desc排序的表結構:

| id  | rank        | votes | url        | created_at          |
+-----+-----------------------------+-----+------------+---------------------+
|  41 | 220.6454978 |  16   | 7X1dqLLNRG | 2016-04-24 08:02:03 |
|  32 | 192.6005579 |  15   | k39djkOGP0 | 2016-04-09 17:49:22 |
|  81 | 401.8382322 |  13   | 7X1dqPLNRG | 2016-07-27 18:04:14 |
|  36 | 192.6460924 |  12   | mZEzDLzxpb | 2016-04-09 19:36:12 |
|  35 | 192.5188647 |   9   | 5ykOxjNBp7 | 2016-04-09 19:34:29 |
|  50 | 325.8341567 |   8   | lm2dpyxOQY | 2016-06-18 06:39:19 |
|  34 | 192.4059869 |   7   | EDMOM0d16m | 2016-04-09 19:31:41 |
|  33 | 192.2031068 |   6   | J6RN0mdGmY | 2016-04-09 17:49:44 |
|  57 | 325.5080990 |   3   | 76mz7R1OGl | 2016-06-18 07:54:15 |
|  56 | 325.5039213 |   3   | KE0NQEkN1p | 2016-06-18 07:51:07 |
|  40 | 193.2540546 |   3   | 796Na28dJr | 2016-04-10 10:43:43 |
|  39 | 193.2262101 |   3   | 6yMNr0Ox-Y | 2016-04-10 10:22:50 |
|  38 | 193.2205435 |   3   | Y21OmeODEp | 2016-04-10 10:18:35 |
|  55 | 325.3238522 |   2   | e4Bd3xoOjg | 2016-06-18 07:48:08 |
|  54 | 325.3145633 |   2   | Z56zRyqOYM | 2016-06-18 07:41:10 |
|  53 | 325.2995633 |   2   | G3JdEMGd0y | 2016-06-18 07:29:55 |
|  52 | 325.2952967 |   2   | gm8dna7Noq | 2016-06-18 07:26:43 |
|  49 | 323.1741856 |   2   | -41zKQndp3 | 2016-06-17 04:55:53 |
|  48 | 323.1371411 |   2   | obmd2DLze2 | 2016-06-17 04:28:06 |
|  47 | 322.2090522 |   2   | 2KGdGR-N9j | 2016-06-16 16:52:02 |
|  45 | 318.4326967 |   2   | ngYN4lRNDB | 2016-06-14 17:39:46 |
|  42 | 244.7367189 |   2   | -arOeX3dby | 2016-05-07 08:27:47 |
|  27 | 191.1572300 |   2   | 7rbzy5zXGm | 2016-04-09 10:43:10 |
|  20 | 183.1333856 |   2   | PE4N13Oa-r | 2016-04-05 06:25:17 |
| 102 | 430.7966222 |   1   | -arOe3mNby | 2016-08-12 09:58:29 |
|  93 | 415.2774667 |   1   | G3JdEjGO0y | 2016-08-04 07:59:07 |
|  80 | 397.8948667 |   1   | 796NaX8zJr | 2016-07-26 06:42:10 |
|  79 | 397.0725111 |   1   | 6yMNrm0zx- | 2016-07-25 20:25:24 |
|  77 | 397.0368667 |   1   | j3-Ob8aN9k | 2016-07-25 19:58:40 |
|  75 | 388.2400889 |   1   | 5ykOxQjzBp | 2016-07-21 06:01:05 |
|  72 | 386.3236889 |   1   | k39djBkdGP | 2016-07-20 06:03:47 |
|  65 | 378.7166889 |   1   | B0kd5bkO7L | 2016-07-16 06:58:32 |
|  64 | 367.0564222 |   1   | l16zlkxOqe | 2016-07-10 05:13:20 |
|  63 | 365.7214000 |   1   | qBEdkk2d2M | 2016-07-09 12:32:04 |
|  62 | 354.0362889 |   1   | Xk3O-1jOEY | 2016-07-03 10:28:14 |
|  61 | 354.0347556 |   1   | kryNP1Kd9a | 2016-07-03 10:27:05 |
|  60 | 353.5897333 |   1   | PE4N123da- | 2016-07-03 04:53:19 |
|  58 | 329.7797111 |   1   | J-azJQ2Oeb | 2016-06-20 19:15:48 |
|  44 | 257.9238889 |   1   | jexdZ0JzR5 | 2016-05-14 09:03:56 |
|  59 | 350.6545778 |   0   | QK2N6yKzn6 | 2016-07-01 16:11:57 |
|  51 | 324.9408000 |   0   | 2P8O8P-Opm | 2016-06-18 06:46:37 |
|  46 | 321.4635111 |   0   | Da8zBj6z-Y | 2016-06-16 11:18:39 |
|  43 | 249.2581556 |   0   | e6XOLJENQ3 | 2016-05-09 20:44:38 |
|  92 | 413.8514933 | -26   | gm8dn07zoq | 2016-08-04 07:50:52 |

模型中的after方法

public function scopeAfter($query, self $post)
{
    return $query->orderBy('votes', 'desc')
        ->latest()
        ->where('status', '=', 'approved')
        ->where('id', '<>', $post->id)
        ->where('votes', '<=', $post->votes)
        ->where('created_at', '<=', $post->created_at);
}

控制器:

$posts=null;
if(isset($req['before'])){
 //...
} elseif (isset($req['after'])){
    $prevPost = Post::where('url','=',$req['after'])->first();
    $posts= Post::after($prevPost)
        ->with('categories', 'voted')
        ->with(array('user'=>function($q){
            $q->select('id', 'img','nick', 'points', 'slug');
        }))
        ->limit(10)
        ->get();
} else {
    // if no params, get the first 10
    $posts= Post::with('categories', 'voted')
        ->with(array('user'=>function($q){
            $q->select('id', 'img','nick', 'points', 'slug');
        }))
        ->where('status','=','approved')
        ->orderBy('votes', 'desc')
        ->orderBy('created_at', 'desc')
        ->limit(10)
        ->get();
}

//return $posts;

視圖鏈接

<a href="{{url('/ordered-by-votes') . '?' . http_build_query(['after' => $lastPost->url])}}" class="btn after">< Previous</a>
<a href="{{url('/ordered-by-votes') . '?' . http_build_query(['before' => $firstPost->url])}}" class="btn before">Before ></a>

更新3

應該有5頁,44個結果,但只顯示3頁和27個結果。

第1頁 - 正確 - 10個結果

from 7X1dqLLNRG to KE0NQEkN1p

第2頁 - 正確 - 10個結果

from 796Na28dJr to 2KGdGR-N9j

第3頁 - 不正確 - 只有7個結果以錯誤的順序顯示

ngYN4lRNDB (OK)
-arOeX3dby (OK)
7rbzy5zXGm (OK)
PE4N13Oa-r (OK)
jexdZ0JzR5 (NOT OK)
Da8zBj6z-Y (NOT OK)
e6XOLJENQ3 (NOT OK)

以下是您使用代碼的方法:

// controller
$post = Post::findByWhateverYouWant($key_from_route);

// higher ranked:
$paginator = Post::before($post)
                 ->with('categories', 'votes')
                 ->simplePaginate(20);

// you need to reverse this result in order to sort 
// appropriately but AFTER the query was executed   
return $paginator->setCollection($paginator->reverse());




// lower ranked:
return Post::after($post)
           ->with('categories', 'votes')
           ->simplePaginate(20);

這里是提到范圍的模型:

public function scopeBefore($query, self $post, $sortBy = 'votes')
{
    return $query->orderBy($sortBy)
                 ->orderBy('created_at')
                 ->where('id', '<>', $post->id)
                 ->where(function ($q) use ($post, $sortBy) {
                    $q->where($sortBy, '=', $post->{$sortBy})
                      ->where('created_at', '>=', $post->created_at)
                      ->orWhere($sortBy, '>', $post->{$sortBy});
                 });
}

public function scopeAfter($query, self $post, $sortBy = 'votes')
{
    return $query->orderBy($sortBy, 'desc')
                 ->latest()
                 ->where('id', '<>', $post->id)
                 ->where(function ($q) use ($post, $sortBy) {
                    $q->where($sortBy, '=', $post->{$sortBy})
                      ->where('created_at', '<=', $post->created_at)
                      ->orWhere($sortBy, '<', $post->{$sortBy});
                 });
}

您可以向這些范圍添加第3個參數,以便根據需要進行 2nd column自定義。

使用這樣的東西(你沒有共享任何代碼,所以把你的模型和變量放在這里):

$perPage = 20;
$toSkip = $id_of_post_to_start_from - $perPage;
$toSkip = $toSkip < 0 ? 0 : $toSkip;
$prevousTwentyPosts = Post::orderBy('rank', 'desc')->skip($toSkip)->take($perPage)->get();

要做到這一點:

有沒有辦法從一個帖子的ID開始檢索前20個帖子,同時按排名排序

我不知道我是否正確,但你不能只使用where('id','>',$ id)?

編輯:nvm,您希望對所有結果進行分頁,以便您無法在哪里使用。

我原以為你可以通過將當前的id轉換為排名,然后在rank上添加where子句並最終獲取所需的記錄數來解決這個問題。

$posts = Post::with(array('user'=>function($q){
            $q->select('id', 'img','nick', 'points', 'slug');
        }))
       ->with('categories')
       ->with('voted')

       ->where('rank', '>', function($q) use ($id){
           $q->select('rank')
             ->from('posts')
             ->where('id', $id);
       })

       ->orderBy('rank', 'DESC')
       ->orderBy('created_at','DESC')
       ->take(20);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM