使用activerecord和RoR3获取没有相关数据的记录?

时间:2015-10-16 18:42:22

标签: ruby-on-rails-3 activerecord

我正在为scopes制作一个看起来像这样的模型:

class PressRelease < ActiveRecord::Base
  has_many :publications
end

我想得到的是press_releases所有publications,但没有scope,而是来自present?方法,所以它可以与其他范围链接。有什么想法吗?

谢谢!

注意:我知道有any?ActiveRecord::Relation等方法,但这些方法不会像范围那样返回laser.physicsBody!.dynamic = false

注意:我使用的是RoR 3

4 个答案:

答案 0 :(得分:1)

如果您不需要,请避免使用eager_loading(这会增加开销)。此外,不需要子选择语句。

scope :without_publications, -> { joins("LEFT OUTER JOIN publications ON publications.press_release_id = press_releases.id").where(publications: { id: nil }) }

对评论的解释和回应

我对初步加载开销的初步想法是,ActiveRecord会为每个新闻稿实例化所有子记录(出版物)。然后我意识到查询永远不会返回带有出版物的新闻稿记录。所以这是一个有争议的问题。

关于ActiveRecord的工作方式,有一些要点和观察。我之前从经验中学到的一些东西,以及我学会探索你的问题的一些事情。

来自includes(:publications).where(publications: {id: nil})的查询实际上与我的示例不同。除了publications中的列之外,它还将返回press_releases表中的所有列。发布列完全没有必要,因为它们始终为null。但是,两个查询最终都会生成相同的PressRelease个对象集。

使用includes方法,如果添加任何类型的限制,例如链接.first.last.limit(),则ActiveRecord(4.2.4)将执行两个查询。第一个查询返回ID,第二个查询使用这些ID获取结果。使用SQL片段方法,ActiveRecord只能使用一个查询。以下是我的一个应用程序的示例:

Profile.includes(:positions).where(positions: { id: nil }).limit(5)
# SQL (0.8ms)  SELECT  DISTINCT "profiles"."id" FROM "profiles" LEFT OUTER JOIN "positions" ON "positions"."profile_id" = "profiles"."id" WHERE "positions"."id" IS NULL LIMIT 5
# SQL (0.8ms)  SELECT "profiles"."id" AS t0_r0, ..., "positions"."end_year" AS t1_r11 FROM "profiles" LEFT OUTER JOIN "positions" ON "positions"."profile_id" = "profiles"."id" # WHERE "positions"."id" IS NULL AND "profiles"."id" IN (107, 24, 7, 78, 89)

Profile.joins("LEFT OUTER JOIN positions ON positions.profile_id = profiles.id").where(positions: { id: nil }).limit(5)
# Profile Load (1.0ms)  SELECT  "profiles".* FROM "profiles" LEFT OUTER JOIN positions ON positions.profile_id = profiles.id WHERE "positions"."id" IS NULL LIMIT 5

最重要的是

eager_loadingincludes无意解决手头的问题。对于这个特殊情况,我认为你比ActiveRecord更了解需要什么。因此,您可以更好地决定如何构建查询。

答案 1 :(得分:0)

您可以在PressRelease中找到以下内容:

scope :your_scope, -> { where('id NOT IN(select press_release_id from publications)') }

这将返回没有出版物的所有PressRelease记录。

答案 2 :(得分:0)

如何做到这一点,首先需要两个数据库查询:

PressRelease.where.not(id: Publications.uniq.pluck(:press_release_id))

或者如果您不想硬编码关联外键:

PressRelease.where.not(id: PressRelease.uniq.joins(:publications).pluck(:id))

另一个是进行左连接并选择那些没有关联元素的东西 - 你得到一个关系对象,但是因为它已经有了一个连接,所以使用它会很棘手:

PressRelease.eager_load(:publications).where(publications: {id: nil})

另一个是使用counter_cache功能。您需要在publication_count表格中添加press_releases列。

class Publications < ActiveRecord::Base
  belongs_to :presss_release, counter_cache: true
end

Rails会使此列与与给定模式关联的多个记录保持同步,因此您可以执行以下操作:

PressRelease.where(publications_count: [nil, 0])

答案 3 :(得分:0)

另一种(更快)的方法是使用Counter Cache。

您可以在http://railscasts.com/episodes/23-counter-cache-column

了解更多相关信息

那么查询会很简单;)