[英]How can I optimize this Query with Rails
I have an array of book ids and I need to iterate each and save the number of comments for each in a Hash (@book_comments) that will have the book_id as the key and the number of comments for that book as a value.我有一个书籍 id 数组,我需要迭代每个并将每个人的评论数量保存在一个哈希(@book_comments)中,该哈希将 book_id 作为键,并将该书的评论数量作为值。 Book has many comments, comment belong to books.
书上有很多评论,评论属于书。
@book_ids.map {|id| @book_comments[id] = Book.find(id).comments.size}
This will hit the DB with these two queries for the amount of ids I have on my array.这将通过这两个查询访问数据库,以获取我在阵列上的 ID 数量。
SELECT `books`.* FROM `books` WHERE `books`.`id` = ? LIMIT 1
SELECT COUNT(*) FROM `comments` WHERE `comments`.`book_id` = ?
Surely there's a better way.肯定有更好的方法。 If you know, please teach me.
知道的请教教我。 Thank you.
谢谢你。
这应该得到你的哈希:
@book_comments = Comment.where(book_id: @book_ids).group(:book_id).count
Use this code:使用此代码:
comment_counts_by_book = Book.select('books.id, count(comments.id) as comments_count').
joins('left outer join comments on comments.book_id = books.id').
group('books.id').inject({}) { |h, book| h[book.id] = book.comments_count; h }
comment_counts_by_book
# => {1=>2, 2=>5, ...}
It does a single database query returning Book
objects with only :id
and :comments_count
attributes filled out.它执行单个数据库查询,返回仅填写
:id
和:comments_count
属性的Book
对象。 The result is then transformed using inject
to a hash with book ids as keys and comments counts as values.然后使用
inject
将结果转换为以书籍 ID 作为键和评论作为值的散列。
If you're using Rails 4 you can do the following as well:如果您使用的是 Rails 4,您也可以执行以下操作:
Comment.eager_load(:book).group(:book).count
It'll generate something like this:它会产生这样的东西:
=> #{1=>2, 2=>4, 3=>9}
Does this work for you?这对你有用吗? I'm not sure if I understood the question correctly.
我不确定我是否正确理解了这个问题。 Let me know.
让我知道。
Book.find(@book_ids).map(&:comments).size
Is this closer to what you want?这是否更接近你想要的?
@book_ids.map do |id|
{
id => Book.find(id).map(&:comments).size
}
end
{}.tap do |hash|
@book_ids.each do |book_id|
hash[book_id] = Book.find(book_id).map(&:comments).size
end
end
You should use includes to eager load the comments then iterate over that query.您应该使用包含来预先加载评论,然后遍历该查询。
books = Book.where(id: @book_ids).includes(:comments)
books.each do |book|
@book_comments[book.id] = book.comments.length
end
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.