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

2

10

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

Quincey answered 7/5, 2012 at 8:29 Comment(0)
Q
6

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

Quincey answered 9/5, 2012 at 10:56 Comment(2)
Has this been implemented yet? Does an issue on GitHub exist for this?Aardvark
This has been added with the pluck command. User.all.pluck(:id). Credit to @bosskovic here https://mcmap.net/q/792014/-rails-mongoid-criteria-find-by-associationGpo
K
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.

Kingpin answered 7/5, 2012 at 19:51 Comment(1)
Thanks, that's an interesting approach. I had considered it (not with mongoid_denormalize that I did not know), but general denormalization. The reason why I decided to not go with it, is that the need of displaying the project's user email is rare and most used in an internal admin interface. The issue comes with the fact that it's paginated with a lot of projects, there requiring a lot of user load. Which is why a .only() would solve my particular problemQuincey

© 2022 - 2024 — McMap. All rights reserved.