Rails has_many关联计数子行

时间:2009-04-28 03:48:48

标签: ruby-on-rails grouping has-many

有效获取父表的所有行以及每行的子数计数的“轨道方式”是什么?

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

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

我希望能够提取每篇文章在过去一小时,一天,一周内的评论数量。

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

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

我知道我可以硬编码完整的SQL,也许可以使用.find并只设置:joins:group:conditions参数...但我想知道是否有“更好”的方式......又称“铁路方式”

提前致谢

5 个答案:

答案 0 :(得分: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'
            )

这将返回一个文章对象列表,每个文章对象都有方法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

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

+----+----------------+------------+
| id | text           | post_count |
+----+----------------+------------+
|  1 | TEXT TEXT TEXT |          1 |
|  2 | TEXT TEXT TEXT |          3 |
|  3 | TEXT TEXT TEXT |          0 |
+----+----------------+------------+

答案 1 :(得分:9)

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" )

感谢Rails 2版本的Gdeglin

答案 2 :(得分:5)

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

在我的模型中,我做了:

class Article < ActiveRecord::Base
  has_many :posts

  def count_posts
    Post.where(:article_id => self.id).count
  end
end

现在,您可以使用例如:

Articles.first.count_posts

我不确定它是否可以更有效率,但它的解决方案在我看来比其他方式更优雅。

答案 3 :(得分:4)

从SQL的角度来看,这看起来微不足道 - 只需编写一个新查询。

从Rails角度来看,您提到的值是计算值。因此,如果使用find_by_sql,Model类将不知道计算字段,因此即使您设法将查询转换为Rails发言,也会将计算值作为字符串返回。请参阅下面的链接问题 一般的偏差(从我得到的问题的反应)是有一个单独的类负责汇总/计算所需的值。

How to get rails to return SUM(columnName) attributes with right datatype instead of a string?

答案 4 :(得分:0)

我以这种方式完成这项工作:

def show
  section = Section.find(params[:id])
  students = Student.where( :section_id => section.id ).count
  render json: {status: 'SUCCESS', section: students},status: :ok
end

在此,我有2个模型部门和学生。因此,我必须计数与特定部分ID相匹配的学生人数。

相关问题