2

假设您在其中一个模型中有一个关联,如下所示:

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
}

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

我的问题是:有什么方法(例如一些 gem)可以通过确保您简单地指定关联条件来消除此问题的方式编写此代码,并且应用程序本身将决定是否需要执行另一个数据库查询或不是?

ActiveRecord 本身似乎并没有适当地解决这个问题。您被迫在每次查询数据库或将关联视为数组之间做出决定。

4

2 回答 2

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 版本,但只计算一次

但是,即使您不使用它,它也不会简化最初的 30 天查询。够了吗,还是需要更多?

于 2013-04-22T16:14:53.543 回答
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)

你可以做一个小组。

归根结底是您需要分析您的代码并确定对您的应用程序来说最快的是什么(或者您是否应该为此烦恼)

于 2013-04-22T12:40:28.567 回答