Rails has_many关联计数子行

SWR*_*SWR 27 grouping ruby-on-rails has-many

什么是有效抓取父表的所有行的"轨道方式"以及每行的子节点数?

我不想使用,counter_cache因为我想根据一些时间条件运行这些计数.

陈词滥调的博客示例:文章表.每篇文章都有0条或更多条评论.

我希望能够提取每篇文章在过去一小时,一天,一周中有多少评论.

但是,理想情况下,我不想迭代列表并为每篇文章单独调用sql,也不想使用它:include来预取所有数据并在应用服务器上处理它.

我想运行一个SQL语句并获得一个包含所有信息的结果集.

我知道我可以硬编码了完整的SQL,也许可以使用.find,只是设置:joins,:group:conditions参数......但我想知道如果有一个"更好"的方式......又名"轨道办法"

提前致谢

Gde*_*lin 28

这个activerecord调用应该做你想要的:

Article.find(:all, :select => 'articles.*, count(posts.id) as post_count',
             :joins => 'left outer join posts on posts.article_id = articles.id',
             :group => 'articles.id'
            )
Run Code Online (Sandbox Code Playgroud)

这将返回一个文章对象列表,每个文章对象都有一个方法post_count,其中包含文章中作为字符串的帖子数.

该方法执行类似于以下的sql:

SELECT articles.*, count(posts.id) AS post_count
FROM `articles`
LEFT OUTER JOIN posts ON posts.article_id = articles.id
GROUP BY articles.id
Run Code Online (Sandbox Code Playgroud)

如果您很好奇,这是您在运行此类查询时可能会看到的MySQL结果的示例:

+----+----------------+------------+
| id | text           | post_count |
+----+----------------+------------+
|  1 | TEXT TEXT TEXT |          1 |
|  2 | TEXT TEXT TEXT |          3 |
|  3 | TEXT TEXT TEXT |          0 |
+----+----------------+------------+
Run Code Online (Sandbox Code Playgroud)

  • 对于那些使用PostgreSQL的用户而言,您需要为select和group提供所有检索到的列. (6认同)
  • 在Rails 3中,这将是`Article.select('foo').join('bar').group('baz')`等. (2认同)

Jos*_*ter 10

Rails 3版本

对于Rails 3,你会看到这样的东西:

Article.select( "articles.*, count(comments.id) AS comments_count" )
  .joins( "LEFT OUTER JOIN comments ON comments.article_id = articles.id" )
  .group( "articles.id" )
Run Code Online (Sandbox Code Playgroud)

感谢Gdeglin为Rails 2版本.


Jon*_*ira 5

我用来解决这个问题的一个简单方法是

在我的模型中,我做了:

class Article < ActiveRecord::Base
  has_many :posts

  def count_posts
    Post.where(:article_id => self.id).count
  end
end
Run Code Online (Sandbox Code Playgroud)

现在,您可以使用例如:

Articles.first.count_posts
Run Code Online (Sandbox Code Playgroud)

我不确定它是否可以更有效,但它是一个解决方案,在我看来比其他更优雅.

  • 从文章/索引路径检索文章时,将为返回的每篇文章触发一个计数查询.如果每个计数保守地说0.25毫秒并且你要求100条,那么请求增加25毫秒.因此,如果请求是在你添加它之前的5ms,那么它现在是30ms - 慢6倍.优雅但不高效. (2认同)