29

什么是有效抓取父表的所有行以及每行具有的子表数量的“rails 方式”?

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

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

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

但是,理想情况下,我不想遍历列表并对每篇文章进行单独的 sql 调用,也不想用于:include预取所有数据并在应用服务器上处理它。

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

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

4

5 回答 5

29

这个 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 |
+----+----------------+------------+
于 2009-04-28T06:04:05.287 回答
10

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

感谢Gdeglin提供 Rails 2 版本。

导轨 5 版本

由于 Rails 5 有,left_outer_joins所以您可以简化为:

Article.select("articles.*, count(comments.id) AS comments_count")
  .left_outer_joins(:comments)
  .group("articles.id")

并且因为您在询问 Rails 方式:没有办法使用 ActiveRecord 来简化/简化它。

于 2013-04-03T22:38:54.693 回答
4

从 SQL 的角度来看,这看起来很简单——只需编写一个新查询。

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

如何让 Rails 返回具有正确数据类型而不是字符串的 SUM(columnName) 属性?

于 2009-04-28T05:39:18.247 回答
4

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

在我的模型中,我做了:

class Article < ActiveRecord::Base
  has_many :posts

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

现在,您可以使用例如:

Articles.first.count_posts

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

于 2014-11-22T20:14:53.517 回答
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 匹配的学生人数。

于 2019-04-23T12:22:49.050 回答