Querying embedded documents on a document with MongoMapper
Asked Answered
R

3

6

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 MUST 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?

Rub answered 25/5, 2011 at 16:27 Comment(1)
Sorry i can't answer your question directly (not enough mapper experience) but look at Plucky. It's a query lang on top of MongoDB and maybe it can get you a little more succinct syntax.Outfield
G
0

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.

Gennagennaro answered 27/5, 2011 at 13:28 Comment(0)
E
0

I think Mongoid supports this, see "Finding" in the manual for embedded docs.

Entero answered 25/4, 2012 at 6:5 Comment(0)
U
-1

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
Utimer answered 22/1, 2015 at 20:59 Comment(3)
Yes. There is no answer selected and this is indeed the only way of doing it. Additionally, if its an embedded document, there should not be very many entries by best practice.Utimer
I don't know why you are complaining here? There is only 1 way currently to do what the OP has asked and this is it. If you have a problem with it, why not create a new mongo gem or something solve this? And yes like I said, if you have a ton of items such as alerts, they should not be embedded by best practice. But the OP did not ask for best practices or opinions, just to answer his question...Utimer
There i added a new option of doing this, now go away if you have nothing to add...Utimer

© 2022 - 2024 — McMap. All rights reserved.