我正在为scopes
制作一个看起来像这样的模型:
class PressRelease < ActiveRecord::Base
has_many :publications
end
我想得到的是press_releases
所有publications
,但没有scope
,而是来自present?
方法,所以它可以与其他范围链接。有什么想法吗?
谢谢!
注意:我知道有any?
或ActiveRecord::Relation
等方法,但这些方法不会像范围那样返回laser.physicsBody!.dynamic = false
。
注意:我使用的是RoR 3
答案 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_loading
和includes
无意解决手头的问题。对于这个特殊情况,我认为你比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
了解更多相关信息那么查询会很简单;)