简体   繁体   English

在 Rails 中计算关联记录

[英]Counting associated records in Rails

I am trying to get the number of comments from each of the posts in the database.我正在尝试从数据库中的每个帖子中获取评论数。 The following, however:但是,以下内容:

Post.includes(:comments).group("posts.id").count("comments.id")

raises the mysql error "Unknown column comments.id", since the generated sql seems to completely ignore the includes():引发mysql错误“未知列comments.id”,因为生成的sql似乎完全忽略了includes():

SELECT COUNT(comments.id) AS count_comments_id, posts.id AS posts_id
FROM `posts` GROUP BY posts.id

Interestingly, replacing includes() with joins() will produce working sql:有趣的是,将 includes() 替换为 joins() 将产生有效的 sql:

Post.joins(:comments).group("posts.id").count("comments.id")

SELECT COUNT(comments.id) AS count_comments_id, posts.id AS posts_id
FROM `posts` INNER JOIN `comments` ON `comments`.`post_id` = `posts`.`id`
GROUP BY posts.id

but the above query excludes all posts with 0 comments, which is not what I want.但是上面的查询排除了所有评论为 0 的帖子,这不是我想要的。 What I do need is to produce the following SQL (but without writing SQL, he he he)我需要的是产生以下SQL(但不写SQL,嘿嘿嘿)

SELECT COUNT(comments.id) AS count_comments_id, posts.id AS posts_id
FROM `posts` LEFT OUTER JOIN `comments` ON `comments`.`post_id` = `posts`.`id`
GROUP BY posts.id

The includes method will not do a join in all cases but rather batch-fetch the association for performance reasons (see Rails :include vs. :joins ). includes方法不会在所有情况下都进行连接,而是出于性能原因批量获取关联(参见Rails :include 与 :joins )。

What you need to do is a joins and you where almost on the correct path but got the group clause a bit wrong:你需要做的是一个连接,你几乎在正确的路径上,但组子句有点错误:

Post.select("posts.*, COUNT(comments.id) as comment_count").joins("LEFT OUTER JOIN comments ON (comments.post_id = posts.id)").group("posts.id")

Note that this solution has the benefit or actually returning Post objects (using .count() returns a Hash on my Rails 3.2) so you can loop through actual post objects in your view and also access the property comment_count .请注意,此解决方案具有好处或实际上返回 Post 对象(使用.count()在我的 Rails 3.2 上返回一个 Hash),因此您可以循环查看视图中的实际 post 对象并访问属性comment_count

This problem is actually way simpler nowadays:现在这个问题实际上要简单得多:

Comment.joins(:post).group(:post_id).count(:post_id)

This will give you a map of {<post_id> => <count of comments>}这将为您提供{<post_id> => <count of comments>}的地图

Try this:尝试这个:

Post.select("COUNT(comments.id) AS count_comments_id, posts.id AS posts_id").
  includes(:comments).group("posts.id")

If all you need is the hash of post counts: {post_id1 => cnt1, post_id2 => cnt2, ...} then forcing a left join on the association will work:如果您只需要帖子计数的散列: {post_id1 => cnt1, post_id2 => cnt2, ...}那么在关联上强制左连接将起作用:

  Post.joins("LEFT OUTER JOIN comments on posts.id=comments.post_id").
  group("posts.id").count("comments.id")

For rails 5 or above , we have a activerecord method left_outer_joins & we don't need to write the join logic manually.对于rails 5 或更高版本,我们有一个 activerecord 方法left_outer_joins我们不需要手动编写连接逻辑。

Post.left_outer_joins(:comments)
    .distinct
    .select('posts.*, COUNT(comments.*) AS comments_count')
    .group('posts.id')

Which produces:产生:

SELECT DISTINCT posts.*, COUNT(comments.*) AS comments_count FROM posts 
LEFT OUTER JOIN comments ON comments.post_id = posts.id GROUP BY posts.id

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM