[英]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.