Querying embedded documents on a document with MongoMapper
What is a good pattern for querying embedded documents on a document? For instance, my User document has an embedded Alerts document. If I want to see if a given User has an alert with name I can do it two ways as far as I can tell -- in memory a la
alert = current_user.alerts.select{|a| a.name == params[:name]}.first
or via the actual document interface a la (note that I'm not 100% sure this is semantically valid but you get the point):
User.where('alerts.name' => params[:name], :id => current_user.id).first
There MU开发者_JS百科ST be a better way, something like
current_user.alerts.where(:name => params[:name])
perhaps? Or maybe I'm just not thinking about the problem right?
Nope. And I think this is the motivation:
In MongoMapper, queries on the database always return a root object. Allowing queries to return an embedded doc without its parent would be a break with that and make a lot of things more complicated (what if I call .parent inside that embedded doc?) so MongoMappers errs on the side of simplicity and doesn't pretend that things are something they aren't. Embedded docs are stored in an array inside the root doc in MongoDB, so MongoMapper gives you an array in Ruby.
So your two ways of doing it are the intended ways of doing it.
If you need some syntactic suger, it shouldn't be too hard to code up. You could extend Array or you could code a plugin to expand upon MongoMapper's proxy for embedded docs.
I think Mongoid supports this, see "Finding" in the manual for embedded docs.
You can do either:
User.where('alerts.name' => params[:name], :id => current_user.id).fields(:alerts).first.alerts.select{|u| u.name == params[:name]}
or
User.where('alerts.name' => params[:name], :id => current_user.id).fields(:alerts).alerts.select{|u| u.name == params[:name]}.first
精彩评论