indexes on sub-collections

12 views
Skip to first unread message

samullen

unread,
Nov 12, 2009, 10:03:53 AM11/12/09
to MongoMapper
I'm just curious how I would go about indexing "sub-collections" (not
sure what to call those).

Example:
I have a user collection. Users can have followers and be followers
(following) of other users.

class User
include MongoMapper::Document

<user fields>

many :followers
many :followings
end

class Follower
include MongoMapper::Document

key :follower_id, String, :required => true
key :blocked, Boolean, :default => false
timestamps!
end

class Following
include MongoMapper::Document

key :following_id, String, :required => true
timestamps!
end

So how do I index the followers/followings? Do I put them in the
respective classes
MongoMapper.ensure_index(Follower, :following_id, :unique => true)
MongoMapper.ensure_indexes!

or do I put the indexes in the User table? If I do this, is it the
same syntax as previous?

Thanks,
Samuel

John Nunemaker

unread,
Nov 12, 2009, 10:34:46 AM11/12/09
to mongo...@googlegroups.com
In the respective classes. All the many does is create associations
that do querying for you behind the scenes.

Also, don't use MongoMapper.ensure_index directly. Just put your
indexes in your model. For example, in the following model you could
do this:

key :following_id, String, :required => true, :index => true

or you could do this...

ensure_index :following_id

Also, this gist shows an initializer to use database.yml to store your
database connection settings and ensure that all indexes are created
at boot time in rails.

http://gist.github.com/232953

Hope that helps.

Kyle Banker

unread,
Nov 12, 2009, 10:35:19 AM11/12/09
to mongo...@googlegroups.com
If you're going to model your data in this way, then you'll want to create indexes in both the Follower and Following models on each of the foreign keys.

That said, I think there's a more document-oriented way of modeling this data.  Why not express followers, following, and blocked in the user model itself?


class User
 include MongoMapper::Document

 <user fields>

  key :followers,  Array
  key :following,  Array
  key :blocked,   Array
end

Each of the fields, followers, following, and block, will contain a user id.  If you place a unique index on each of those fields, then queries for all of a user's followers, or for everyone a user is following, can still be efficient.

Find all of Bob's followers:
User.all(:conditions => {:following => @bob.id}

Find everyone Bob is following:
User.all(:conditions => {:following => @bob.id}

Of course, writes are a little more complex, but this is likely a worthwhile tradeoff.

John Nunemaker

unread,
Nov 12, 2009, 10:36:08 AM11/12/09
to mongo...@googlegroups.com
I agree with Kyle and should have stated this. I would use array of ids instead of full models and just index those arrays. We are doing this *a lot* in Harmony an app we are building.

samullen

unread,
Nov 12, 2009, 10:42:35 AM11/12/09
to MongoMapper
Outstanding! Works just like I thought it would. And thanks for the
gist.

Samuel

samullen

unread,
Nov 12, 2009, 10:53:04 AM11/12/09
to MongoMapper
I chose to do full Models because 1) it's not just users which can be
followed; and 2) so I could use model specific methods of said
models.

I may have to rethink things a little more.

Thanks again,
Samuel

Cyril Mougel

unread,
Nov 12, 2009, 1:14:21 PM11/12/09
to mongo...@googlegroups.com
samullen a écrit :

> I chose to do full Models because 1) it's not just users which can be
> followed; and 2) so I could use model specific methods of said
> models.
>
> I may have to rethink things a little more.
>

You can have a embeddedDocument too. With embedded you can have a lot of
data. After with an adequate callback you can update it.

--
Cyril Mougel
http://blog.shingara.fr/

samullen

unread,
Nov 12, 2009, 1:25:10 PM11/12/09
to MongoMapper
Yeah, I didn't quite realize how "many" worked. I thought it built out
the embedded document. I'm going to switch over to using hashes for my
followers and followings. I can bring in blocked at that point.

Samuel

John Nunemaker

unread,
Nov 12, 2009, 1:41:08 PM11/12/09
to mongo...@googlegroups.com
many works with embedded documents or documents. If embedded then it
embeds, if document then it does foreign key type queries.

samullen

unread,
Nov 12, 2009, 2:07:32 PM11/12/09
to MongoMapper
John,

Thanks. I just saw that I was supposed to be using
"MongoMapper::EmbeddedDocument" and not just "MongoMapper::Document".

Hate to be such a nube.

Samuel

Aaron

unread,
Nov 20, 2009, 3:51:15 AM11/20/09
to MongoMapper
I notice when using many the foreign key shouldn't be a string because
the foreign key will be wrapped in quotes.

class User
include MongoMapper::Document

many :posts
end

User.first.posts << Post.new()

User.first.posts # => MONGODB app-development.posts.find
({:user_id=>4b04c9ba9a67c268aa000001}, {})
Notice the key isn't wrapped in quotes.

Then we add the foreign key in Post

class Post
include MongoMapper::Document

key :user_id, String, :required => true, :index => true
end

Post.first # => #<Post user_id: "4b04c9ba9a67c268aa000001">
Notice the key IS wrapped in quotes.
User.first.posts # => [ ]


class Post
include MongoMapper::Document

key :user_id, :required => true, :index => true
end

Pull out the String from the key.
Post.first # => #<Post user_id: 4b04c9ba9a67c268aa000001>
User.first.posts # => [ #<Post user_id: "4b04c9ba9a67c268aa000001"> ]

Maybe I'm missing something here but it works now. Thanks to the
logger I noticed 'many' searches for foreign keys without quotes.

John Nunemaker

unread,
Nov 23, 2009, 9:34:22 AM11/23/09
to mongo...@googlegroups.com
String is only an option for id's and foreign keys for backwards
compatibility. From now on every foreign key should be ObjectId type.

key :user_id, ObjectId, :required => true, :index => true
> --
> You received this message because you are subscribed to the Google
> Groups "MongoMapper" group.
> For more options, visit this group at
> http://groups.google.com/group/mongomapper?hl=en?hl=en

Aaron

unread,
Nov 23, 2009, 4:12:08 PM11/23/09
to MongoMapper
Sorry about that, I was going through a newer post and caught the
ObjectId part right after I posted.

On Nov 23, 4:34 am, John Nunemaker <nunema...@gmail.com> wrote:
> String is only an option for id's and foreign keys for backwards
> compatibility. From now on every foreign key should be ObjectId type.
>
> key :user_id, ObjectId, :required => true, :index => true
>
Reply all
Reply to author
Forward
0 new messages