Reputation: 237
I am in the midst of working on a resume templating app. The project is using Rails 4.0, Devise, MongoDB and bootstrap.
This is how my models are structured right now. I am using Polymorphic associations in order to permit more flexibility as the application grows and Users can have more than one resume. I omitted some of the irrelevant model code and some of the smaller models such as educations, skills that don't pertain to my question:
class User
include Mongoid::Document
include Mongoid::Timestamps
has_many :resumes
has_many :educations, as: :educatable
has_many :skills, as: :skillable
has_many :positions, as: :positionable
has_one :address, as: :addressable
field :name, :type => String
field :email, :type => String, :default => ""
field :encrypted_password, :type => String, :default => ""
validates_presence_of :name
validates_uniqueness_of :name, :email
class Resume
include Mongoid::Document
include Mongoid::Timestamps
belongs_to :user
has_many :educations, as: :educatable
has_many :skills, as: :skillable
has_many :positions, as: :positionable
has_one :address, as: :addressable
field :objective, :type => String
validates_presence_of :objective
end
I am implementing the following features to start out:
A friend suggested that MongoDB was meant to enable each model store the data it needs rather than access it through a relationship. In this case, he suggested that I should enable the resume model to store the positions, educations, skills and address in addition to the user model. Having only worked with an RDBMS, I am a bit stuck with how to proceed regarding the 'User can create a resume' feature and am wondering if anyone can suggest how I should model this?
Here is a snapshot of my routes as well:
Tecume::Application.routes.draw do
devise_for :users, :controllers => { :registrations => "registrations"}
resources :users do
resources :resumes, only: [:show, :new, :create]
end
root 'pages#home'
get '/ui/:action', controller: 'ui'
end
Upvotes: 0
Views: 286
Reputation: 434965
Comments are too small so I'll do some hand waving in an answer instead.
Your friend is talking about embedded documents:
embeds_one
instead of has_one
.embeds_many
instead of has_many
.A Mongoid object is basically a Hash wrapped up in a class. Of course, an ActiveRecord object is pretty much the same thing. But, MongoDB makes it easy to have Hash fields and Array fields; if you wrap one of those Hash fields in a class then you pretty much have a embeds_one
relationship; if you populate an Array field with Hashes and wrap them all up in classes then you pretty much have an embeds_many
relationship.
MongoDB doesn't have JOINs so if you need to query two things at once they either you denormalize and copy the data or you embed one thing inside the other. For example, if you want to find all the resumes from people in Whistler and you're using has_one
, then you have to go find all the addresses whose city is Whistler:
addr_ids = Address.where(:city => 'Whistler').pluck(:id)
and then do a separate query to find the resumes:
Resume.where(:address_id.in => addr_ids)
If you use an embedded document then you just look inside the embedded documents:
Resume.where('address.city' => 'Whistler')
Similarly for eager loading: embedded documents come out of the database as part of their parent document, non-embedded documents require separate queries.
Rough rules of thumb: If something needs to be an entity unto itself then traditional has_many
and has_one
relationships make sense, if something only exists in relation to something else then embeds_one
or embeds_many
make sense.
Upvotes: 1