Reputation: 3213
I have the following model:
class User
include Mongoid::Document
store_in :users
field :full_name, :type => String
end
class Message
include Mongoid::Document
embeds_one :sender, :class_name => "User"
field :text, :type => String
end
I would like to store User
and Message
in separated standalone collections so that they could be queried directly, and I would like to have one copy of user for sender
in each Message entry. Is my model correct for this kind of request?
And when I have an instance of User user
, how could I query the messages where sender = user
?
I've tried:
Message.where(:sender => user)
Message.where('sender.id' => user.id)
both not work.
only Message.where('sender.full_name' => user.full_name)
worked, but I don't want to rely on a text field when there's an id field to use.
What's the best way to do that?
How I save Message/User:
user = User.new
user.full_name = 'larry'
user.save
m = Message.new(:text => 'a text message')
m.sender = user
m.save
And it results in the database:
> db.users.find({ 'full_name' : 'larry'})
> db.messages.find({})[0]
{
"_id" : ObjectId("4f66e5c10364392f7ccd4d74"),
"text" : "a text message",
"sender" : {
"_id" : ObjectId("4f62e0af03642b3fb54f82b0"),
"full_name" : "larry"
}
}
Upvotes: 0
Views: 733
Reputation: 46914
Like explain by Jordan Durran ( Mongoid lead developer ) in Google group of Mongoid : http://groups.google.com/group/mongoid/browse_thread/thread/04e06a8582dbeced#
You're going to need a separate model if you want to embed the user data inside the message. When denormalizing like this I generally namespace one of them, and create a module with the common fields to include in both - maybe in your case you can call it Sender?
class Sender
include Mongoid::Document
include UserProperties
class << self
def from_user(user)
Sender.new(user.attributes)
end
end
end
class User
include Mongoid::Document
include UserProperties
end
module UserProperties
extend ActiveSupport::Concern
included do
field :full_name, type: String
end
end
class Message
include Mongoid::Document
embeds_one :sender
end
You also don't need the :store_in macro on User - by default it's name would be "users".
Upvotes: 1
Reputation: 46914
You can't do what you do.
Your user document is save in his one collection because you use the store_in
method. And you try save it on an other document ( Message
)
If you really want 2 collections, you need use has_one :user
in your Message
class.
class Message
has_one :sender, :class_name => 'User', :foreign_key => 'sender_id'
end
After you can get your message like :
Message.senders
to have all of your sender.
Upvotes: 1