这是关于在codeschool观看视频的视频,以及通过合并方法Chris Oliver观看视频的后续问题。
我要做的只是查找至少有一个authors
可用的book
。然后在对authors
进行过滤后,我希望为所选的books
加载所有authors
,因为每次我提取数据时都不想查询数据库图书。我尝试了许多不同的范围,但没有一个能够完全满足我的需求:
#app/models/book.rb
class Book < ActiveRecord::Base
belongs_to :author
scope :available, ->{where(availability: true)}
scope :unavailable, ->{where(availability: false)}
end
#app/models/author.rb
class Author < ActiveRecord::Base
has_many :books, dependent: :destroy
scope :with_available_books, ->{joins(:books).merge(Book.available)}
scope :with_available_books_uniq, ->{uniq.joins(:books).merge(Book.available)}
scope :with_available_books_includes, ->{joins(:books).merge(Book.available).includes(:books)}
scope :with_available_books_uniq_includes, ->{uniq.joins(:books).merge(Book.available).includes(:books)}
def to_s
self.name
end
end
以下是我的数据库中的内容的快照
我有三 authors
:
Neil
,他共有10本相关书籍,所有可用 John
,他共有10本相关图书,所有资料不可用 Mixture Author
,他共有10本书, 5个可用,5个不可用 我运行了所有查询并以HTML格式输出结果。这是我得到的:
# Duplicating the authors AND N + 1 problem with associated books
Author.with_available_books.size:15
作者书籍[0]:10
作者[1]
的书籍:10
# Fixed the duplication but still N + 1 problem with the associated books
Author.with_available_books_uniq.size:2
作者书籍[0]:10
作者[1]
的书籍:10
# Fixed the N + 1 problem but duplicating authors
Author.with_available_books_includes.size:15
# Fixed the duplication and fixed the N + 1 problem
# BUT now it is filtering out the unavailable books!
# But I want all the Books for these authors!
Author.with_available_books_uniq_includes.size:2
作者书籍[0]:10
作者[1]
的书籍:5
我如何抓住所有书籍的重复作者?我想按照关联对象的属性(书籍上的available
属性)过滤作者,我想热切地加载这些书。
答案 0 :(得分:0)
非常感谢Chris Oliver自己回复我关于此情况的电子邮件查询。
首先抓住作者:
@uniq_authors_with_available_books = Author.with_available_books_uniq
这可以正确地抓住两个都有可用图书的Neil
和Mixture Author
:
2.2.1 :004 > @authors_with_available_books.size
=> 2
但是,如下所示,如果我们想要获取有关这两位作者的任何信息,N + 1
问题仍然存在。书:
2.2.1 :005 > @authors_with_available_books[0].books.size
(0.2ms) SELECT COUNT(*) FROM "books" WHERE "books"."author_id" = ? [["author_id", 1]]
=> 10
2.2.1 :006 > @authors_with_available_books[1].books.size
(0.2ms) SELECT COUNT(*) FROM "books" WHERE "books"."author_id" = ? [["author_id", 3]]
=> 10
感谢克里斯的建议。我们要做的是使用subquery
中的id
来@authors_with_available_books
对书籍进行单独查询:
2.2.1 :007 > @books_by_those_authors = Book.where(author_id: @authors_with_available_books.map(&:id))
Book Load (0.4ms) SELECT "books".* FROM "books" WHERE "books"."author_id" IN (1, 3)
从SQL查询中我们可以看到它只抓取id
等于1
或3
的图书。它只是抓住那些作者,因为第一个问题告诉我们只有那些作者才有可用的书籍。
现在我可以这样做:
@books.size
=> 20
这是有道理的,因为Neil
总共有10本书,Mixture Author
总共有10本书,总共合计20
。