Mongoid: How to load only some fields of an object

2019-02-21 13:22发布

问题:

For performance reason, I use as often as possible the only() keyword when writing up a mongoid query in order to specify the fields I want to load.

The usual suspect, is for instance when I want a user's email of all my admins only for display purposes.

I would write:

User.where(:groups => :admins).only(:email).each do |u|
 puts u.email
end

I do this because my user model are quite full of a lot of data that I can gladly ignore when listing a bunch of emails.

However, now let imagine, that my users are referenced via a Project model, so that for each project I can do: project.user. Thanks to mongoid's lazy loading, my object user will only get instantiated (and queried from the DB) when I call upon the reference.

But what if I want to list all the email of the owner of all admin project for instance ?

I would write this:

Project.where(:admin_type => true).each do |p|
  puts p.user.email
end

The major problem here is that doing this, I load the entire user object for each projects, and if there are lots of project matching the query that could get pretty heavy. So how do I load only the emails ?

I could do this:

User.where(:_id => p.user_id).only(:email).first.email

But this obviously defeat the purpose of the nice syntax of simply doing:

p.user.email 

I wish I could write something like: p.user.only(:email).email, but I can't. Any ideas ?

Alex

回答1:

Answer from creator of Mongoid. It's not possible yet. It's been added as feature request.



回答2:

I think you need to denormalize here. First of all, read A Note on Denormalization.

You can implement denormalization by self using mongoid events or use great mongoid_denormalize gem. It pretty straight and after implementing it you could use p.user_email or something in your queries.