Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoid: How to load only some fields of an object you lazy load via reference?

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

like image 686
Alex Avatar asked May 07 '12 08:05

Alex


2 Answers

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

like image 186
Alex Avatar answered Oct 23 '22 06:10

Alex


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.

like image 34
asavartsov Avatar answered Oct 23 '22 06:10

asavartsov