The easiest way to explain this conundrum is with an example:
Say I have two Mongoid models which are related via a has_many
relationship:
A Blog post
class Post
include Mongoid::Document
field :body, type: String
has_many :comments
end
and it's comments
class Comment
include Mongoid::Document
field :text, type: String
belongs_to :post
end
Now I create a Post which has two comments in IRB, and I attempt to load them via the relationship. I have some DB logging enabled so I can see when the query is made:
post.comments #=>
2016-04-27 13:51:52.144 [DEBUG MONGODB | localhost:27017 | test.find | STARTED | {"find"=>"comments", "filter"=>{"post_id"=>BSON::ObjectId('571f315e5a4e491a6be39e02')}}]
2016-04-27 13:51:52.150 [DEBUG MONGODB | localhost:27017 | test.find | SUCCEEDED | 0.000492643s]
=> [#<Comment _id: 571f315e5a4e491a6be39e03, text: 'great post' >, #<Comment _id: 571f315e5a4e491a6be39e12, text: 'this!' >]
So the comments are loaded from the DB and returned as a Mongoid::Relations::Targets::Enumerable
class, which looks like an array, and it contains the two comments.
Now when I open a fresh IRB console, and take a look at the criteria used to load these comments using the criteria
attribute of the Mongoid::Relations::Targets::Enumerable
class instance post.comments
, I get this output:
post.comments.criteria #=>
=> #<Mongoid::Criteria
selector: {"post_id"=>BSON::ObjectId('571f315e5a4e491a6be39e02')}
options: {}
class: Comment
embedded: false>
How come no DB requests is made in this example? It's not a caching problem as I opened a new IRB console.
How can chaining criteria
onto post.comments
change what the .comments
method does?
I took a look through Mongoid's implementation of the Mongoid::Relations::Targets::Enumerable
class (source on Github), but couldn't find any clues to how it works.
Edit
To clarify the question:
This code, doesn't query the database:
post.comments.criteria
But this code does:
foo = post.comments
post.comments.criteria
How come?