Commit 893efa86 by Arjun Singh

Speed up the active_threads page for a single user by about 1.5-2x by bulking some queries.

parent 449f7a42
......@@ -30,9 +30,14 @@ get "#{APIPREFIX}/users/:user_id/active_threads" do |user_id|
page = [num_pages, [1, page].max].min
paged_active_contents = active_contents.page(page).per(per_page)
paged_active_threads = paged_active_contents.map(&get_thread_id)
.uniq.map(&get_thread)
collection = paged_active_threads.map{|t| t.to_hash(recursive: true)}
paged_thread_ids = paged_active_contents.map(&get_thread_id).uniq
paged_active_threads = CommentThread.find(paged_thread_ids)
# Fetch all the usernames in bulk to save on queries. Since we're using the
# identity map, the users won't need to be fetched again later.
User.only(:username).find(paged_active_threads.map{|x| x.author_id})
collection = paged_active_threads.map{|t| t.to_hash recursive: true}
collection = author_contents_only(collection, user_id)
{
......
......@@ -39,6 +39,22 @@ class Comment < Content
nodes.map{|node, sub_nodes| node.to_hash.merge("children" => hash_tree(sub_nodes).compact)}
end
# This should really go somewhere else, but sticking it here for now. This is
# used to flatten out the subtree fetched by calling self.subtree. This is
# equivalent to calling descendants_and_self; however, calling
# descendants_and_self and subtree both is very inefficient. It's cheaper to
# just flatten out the subtree, and simpler than duplicating the code that
# actually creates the subtree.
def self.flatten_subtree(x)
if x.is_a? Array
x.flatten.map{|y| self.flatten_subtree(y)}
elsif x.is_a? Hash
x.to_a.map{|y| self.flatten_subtree(y)}.flatten
else
x
end
end
def to_hash(params={})
sort_by_parent_and_time = Proc.new do |x, y|
arr_cmp = x.parent_ids.map(&:to_s) <=> y.parent_ids.map(&:to_s)
......@@ -49,15 +65,22 @@ class Comment < Content
end
end
if params[:recursive]
self.class.hash_tree(subtree(sort: sort_by_parent_and_time)).first
subtree_hash = subtree(sort: sort_by_parent_and_time)
# Flatten out the subtree and fetch all users in bulk; makes getting the
# usernames faster. Should probably denormalize usernames.
flattened_subtree = Comment.flatten_subtree(subtree_hash)
User.only(:username).find(flattened_subtree.map{|x| x.author_id})
self.class.hash_tree(subtree_hash).first
else
as_document.slice(*%w[body course_id endorsed anonymous anonymous_to_peers created_at updated_at at_position_list])
.merge("id" => _id)
.merge("user_id" => author.id)
.merge("user_id" => author_id)
.merge("username" => author.username)
.merge("depth" => depth)
.merge("closed" => comment_thread.closed)
.merge("thread_id" => comment_thread.id)
.merge("thread_id" => comment_thread_id)
.merge("commentable_id" => comment_thread.commentable_id)
.merge("votes" => votes.slice(*%w[count up_count down_count point]))
.merge("type" => "comment")
......
......@@ -172,13 +172,13 @@ class CommentThread < Content
def to_hash(params={})
doc = as_document.slice(*%w[title body course_id anonymous anonymous_to_peers commentable_id created_at updated_at at_position_list closed])
.merge("id" => _id, "user_id" => author.id,
.merge("id" => _id, "user_id" => author_id,
"username" => author.username,
"votes" => votes.slice(*%w[count up_count down_count point]),
"tags" => tags_array,
"type" => "thread",
"group_id" => group_id,
"pinned" => pinned?,
"pinned" => pinned,
"endorsed" => endorsed?)
if params[:recursive]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment