When to use embedded documents?

I am trying to figure out how to host my database for the site I'm working on. Here are my models:

class User include MongoMapper::Document // keys here many :items many :likes end class Item include MongoMapper::Document key :name, String, :required => true many :likes end class Like include MongoMapper::EmbeddedDocument key :user_id, String, :required => true end 

I believe Like should be implemented somewhere, but it's hard for me to choose one because of the functionality that I would like to get out of it.

 user = User.first user.likes // should print out all the Items he liked item = Item.first item.likes // so I can count how many people like that item 

Although the problem occurs when using EmbeddedDocument, you lose find and other useful methods, and you cannot use it in both models. Therefore, having it only in Item , I will need to run this (but I can not):

 item = Item.first item.likes.find_by_user_id(User.first._id) 

undefined method find_by_user_id will be thrown. Therefore, if I included it in my User , I still could not do this.

 likes = Like.all // will throw undefined `all` 

So, I have come to a conclusion to possibly do this as follows:

 class Like include MongoMapper::Document key :user_id, String, :required => true key :item_id, String, :required => true belongs_to :user belongs_to :item end 

But it looks like I'm still trying to do something in the old MySQL way. Can someone tell me the most likely way to encode this with MongoMapper?

Thanks in advance!

+4
source share
2 answers

Whether this can be modeled in MongoMapper depends on the availability of data that needs to be stored in the Like model. If, as in your example, there is no data associated with the Like model, there is a way. The latest update for MongoMapper added many-to-many support, although it is still in its early stages.

You would create your models as follows:

 class User include MongoMapper::Document key :name, String, :required => true key :liked_item_ids, Array many :liked_items, :in => :liked_item_ids, :class_name => "Item" end class Item include MongoMapper::Document key :name, String, :required => true many :fans, :class_name => "User", :foreign_key => :liked_item_ids end 

Then you can do:

 >> u = User.new( :name => 'emily' ) >> i = Item.new( :name => 'chocolate' ) >> u.liked_items << i >> u.save >> u.liked_items => [#<Item name: "chocolate", _id: 4b44cc6c271a466269000001>] >> i.fans => [#<User name: "emily", liked_item_ids: [4b44cc6c271a466269000001], _id: 4b44cc6c271a466269000002>] 

Unfortunately, what you cannot do with this setting, add something else from the Item relationship side. However, GitHub has an open problem of creating the correct many :in inverse relationship, which will be used in this case as follows:

 many :fans, :class_name => "User", :source => :liked_items 

On the other hand, if there is information that should be stored in Like , for example, when a user liked an item, there is currently no way to simulate it. The ideal setup in this case (without considering what is supported in MongoMapper right now) will be similar to what you included in your question. You will need all three models with Like built into the User model, and the has_many :through connection to create a link from User to Item . Unfortunately, supporting this in MongoMapper is probably pretty far.

If you want to encourage support for such actions in MongoMapper, you can find out on the mailing list or open the MongoMapper github repository release .

+9
source

you can read the Paste Against Link document at mongodb.org: http://www.mongodb.org/display/DOCS/Schema+Design#SchemaDesign-Embedvs.Reference

+3
source

All Articles