Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mongoid - using includes to select children objects in a 1..N referenced relationship

I have a scenario like this:

blog.posts

where each post belongs to another object, say Tag (in a belongs_to, has_many relationship), so I can do:

tag.posts

To prevent the N+1 problem, I want to be able to do blog.posts, but also grab each tag associated with each post, so that two queries are generated, one for the posts, and one for all the tags (based on each tag_id belonging to the post).

I noticed in mongoid documentation I can do:

Post.includes(:tag).where(:blog_id: blog.id)

which will get me all posts belonging to a blog, and also getting each tag associated with the post and putting in the identity map (provided it is enabled).

The problem is, I want to do:

blog.posts

and somehow redefine the query to do what I want above. Is there a way to do that?

At the moment I'm mitigating this by defining an extension:

has_many :posts do
  def with_tags 
    includes(:tag)
  end
end

so that I do

blog.posts.with_tags

but I would prefer that

blog.posts

does the above by default.

Cheers.

like image 538
stantona Avatar asked May 03 '12 17:05

stantona


1 Answers

You can use scopes to achieve this, particular default scopes. So in your Post model, you can define your model such:

class Post
   belongs_to :tag
   default_scope includes(:tag)
end

That way whenever you do a query to get posts, like Blog.posts, mongoid will also generate a query to get all the tags associated with each post.

like image 193
stantona Avatar answered Nov 14 '22 23:11

stantona