在使用 includes Rails 进行预加载时使用范围合并方法
Use merge method with scope while eager loading with includes Rails
这是在 codeschool on Scopes, as well as watching a video by Chris Oliver 观看有关合并方法的视频的后续问题。
我想做的是只找到那些至少有一个 book
可用的 authors
。然后在过滤那些 authors
之后,我想为那些选择的 authors
加载所有 books
因为我不想每次提取关于这些的数据时都查询数据库图书。我尝试了多种不同的示波器,但其中 none 正是我所需要的:
#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
属性)过滤作者,并且我想预先加载这些书籍。
非常感谢 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
感谢 Chris 的建议。我们要做的是使用 @authors_with_available_books
中的 id
对带有 subquery
的书籍进行单独查询:
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
总共有十本书,而 Mixture Author
总共有十本书,总计 20
。
这是在 codeschool on Scopes, as well as watching a video by Chris Oliver 观看有关合并方法的视频的后续问题。
我想做的是只找到那些至少有一个 book
可用的 authors
。然后在过滤那些 authors
之后,我想为那些选择的 authors
加载所有 books
因为我不想每次提取关于这些的数据时都查询数据库图书。我尝试了多种不同的示波器,但其中 none 正是我所需要的:
#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
属性)过滤作者,并且我想预先加载这些书籍。
非常感谢 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
感谢 Chris 的建议。我们要做的是使用 @authors_with_available_books
中的 id
对带有 subquery
的书籍进行单独查询:
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
总共有十本书,而 Mixture Author
总共有十本书,总计 20
。