簡體   English   中英

具有自定義選擇/聯接/順序的Laravel雄辯模型查詢

[英]Laravel Eloquent Model query with custom select/join/order

我有稱為Post和PostView的模型。 一個帖子可以有多個PostView。 我需要獲取按過去30天內創建的PostViews數量排序的帖子分頁列表。

我可以使用withCount來做到這一點:

// works but S L O W
$posts = Post::withCount(['views' => function($query) {
            $query->where('post_views.created_at', '>=', 'DATE_ADD(CURDATE(), INTERVAL -30 DAY)');
         }])
         ->orderBy('views_count')
         ->paginate(10);

但是,這會產生非常慢的查詢,大約需要24秒。

使用原始sql可以更有效地獲取正確的結果,如何將其轉換為分頁的模型集合?

這將生成正確的查詢以獲取前10個查詢,但結果集合為空。 我認為這與selectRaw

$posts = Post::selectRaw('posts.*, count(post_views.id) as views_count')
           ->join('post_views', function($join) {
                $join->on('posts.id', '=', 'post_views.post_id')
                   ->where('post_views.created_at', '>=', 'DATE_ADD(CURDATE(), INTERVAL -30 DAY)');
            })
            ->groupBy('posts.id')
            ->orderBy('views_count', 'DESC')
            ->take(10)
            ->get();

如果我運行直接在mysql中生成的查詢,我會得到結果:(注意-為簡潔起見,將其截斷為posts.id)

mysql> select posts.id, count(post_views.id) as views_count from `posts` inner join `post_views` on `posts`.`id` = `post_views`.`post_id` and `post_views`.`created_at` >= DATE_ADD(CURDATE(), INTERVAL -30 DAY) group by `posts`.`id` order by `views_count` desc limit 10;
+--------+-------------+
| id     | views_count |
+--------+-------------+
| 150277 |          22 |
|  43843 |           6 |
| 138789 |           4 |
| 180565 |           4 |
|  50555 |           3 |
|   2679 |           3 |
| 188572 |           3 |
| 217454 |           3 |
| 136736 |           3 |
| 126472 |           2 |
+--------+-------------+
10 rows in set (1.26 sec)

任何幫助表示贊賞,謝謝。

查詢應為:

$posts = Post::selectRaw('posts.*, count(post_views.id) as views_count')
           ->join('post_views', function($join) {
                $join->on('posts.id', '=', 'post_views.post_id')
                   ->where('post_views.created_at', '>=', 'DATE_ADD(CURDATE(), INTERVAL -30 DAY)');
            })
            ->groupBy('posts.id')
            ->orderBy('views_count', 'DESC')
            // ->take(10) // no need of this
            //->get(); // will be using paginate
             ->paginate(10);

你有沒有嘗試過

PostViews::where('created_at', '>=', 'DATE_ADD(CURDATE(), INTERVAL -30 DAY)')->groupBy('post_id')->selectRaw('count(*) as post_count')->with('post')->paginate(10);

假設您在created_at上有一個索引

我已經弄清楚了-join-> where子句被轉義並使查詢無效。 不是無效的sql,只是無效的比較,這樣永遠不會有結果。

當然,查詢記錄器沒有顯示出它已被轉義,因此將查詢復制到mysql上是可行的,這使得查找該記錄比原本要困難得多。

這有效:

$posts = Post::select('posts.*', DB::raw('count(post_views.id) as views_count'))
->join('post_views', function($join) {
    $join->on('posts.id', '=', 'post_views.post_id')
        ->where('post_views.created_at', '>=', DB::raw('DATE_ADD(CURDATE(), INTERVAL -30 DAY)'));
    })
->groupBy('posts.id')
->orderBy('views_count', 'DESC')

重要的是: DB :: raw('DATE_ADD(CURDATE(),INTERVAL -30 DAY)')

暫無
暫無

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

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