高效的ActiveRecord关联条件

时间:2013-04-22 10:00:13

标签: ruby-on-rails ruby-on-rails-3 activerecord associations

假设您在其中一个模型中有这样的关联:

class User
  has_many :articles
end

现在假设你需要获得3个数组,一个用于昨天写的文章,一个用于过去7天写的文章,另一个用于过去30天写的文章。

当然你可以这样做:

articles_yesterday = user.articles.where("posted_at >= ?", Date.yesterday)
articles_last7d    = user.articles.where("posted_at >= ?", 7.days.ago.to_date)
articles_last30d   = user.articles.where("posted_at >= ?", 30.days.ago.to_date)

但是,这将运行3个单独的数据库查询。更有效率,您可以这样做:

articles_last30d   = user.articles.where("posted_at >= ?", 30.days.ago.to_date)
articles_yesterday = articles_last30d.select { |article| 
  article.posted_at >= Date.yesterday 
}
articles_last7d    = articles_last30d.select { |article| 
  article.posted_at >= 7.days.ago.to_date
}

现在当然这是一个人为的例子,不能保证数组选择实际上比数据库查询更快,但我们假设它是。

我的问题是:有没有办法(例如某些宝石)以一种方式编写此代码,通过确保您只需指定关联条件来消除此问题,并且应用程序本身将决定是否需要执行另一个数据库查询与否?

ActiveRecord本身似乎没有适当地解决这个问题。您不得不决定每次查询数据库或将关联视为数组。

2 个答案:

答案 0 :(得分:0)

有几种方法可以解决这个问题:

您可以通过在关联定义上指定条件哈希来为所需的每个级别创建单独的关联。然后,您可以简单地为用户查询加载这些关联,并且您将为整个操作命中db 3x,而不是每个用户使用3x。

class User
  has_many articles_yesterday, class_name: Article, conditions: ['posted_at >= ?', Date.yesterday]
   # other associations the same way
end

User.where(...).includes(:articles_yesterday, :articles_7days, :articles_30days)

你可以做一个小组。

它归结为您需要分析您的代码并确定您的应用程序最快的速度(或者您甚至应该为此烦恼)

答案 1 :(得分:0)

您可以摆脱使用以下代码检查查询的必要性。

class User
  has_many :articles

  def article_30d
    @articles_last30d ||= user.articles.where("posted_at >= ?", 30.days.ago.to_date)
  end

  def articles_last7d 
    @articles_last7d ||= articles_last30d.select { |article| article.posted_at >= 7.days.ago.to_date }
  end

  def articles_yesterday 
    @articles_yesterday ||= articles_last30d.select { |article| article.posted_at >= Date.yesterday }
  end

end

它的作用:

  • 如果使用三个中的任何一个
  • ,则只使一个查询最大
  • 在任何情况下仅计算使用过的数组和30d版本,但只计算一次

即使您不使用它,它也不会简化初始的30d查询。这还够,还是需要更多的东西?