Car*_*lZA 6 ruby ruby-on-rails schema-design mongodb mongoid
我正在Rails中构建一个论坛系统,以便更熟悉Rails和Mongoid.我想添加的一个功能是用户可以用来互相发送消息的私人消息系统论坛.在架构设计方面,我可以想到两个解决方案:
用户和消息是使用"has_many"和"belongs_to"相互链接的单独文档.
用户文档
has_many:messages_sent,:class_name =>'Message',:inverse_of =>:message_sender
has_many:messages_received,:class_name =>'Message',:inverse_of =>:message_recipient
和
消息文档
field:created,type:DateTime,default: - > {Time.now}
field:content,type:String
belongs_to:message_sender,:class_name =>'User',:inverse_of =>:messages_sent
belongs_to:message_recipient,:class_name =>'User',:inverse_of =>:messages_received
为了向用户显示他的收件箱,我会查看已some_user.messages_received排序:created并进行过滤,因此我有一个唯一的发件人ID列表,这些列表是在发送最后一封邮件时排序的some_user.
然后,为了显示特定的对话,我只是获取两个参与者之间的所有消息,并根据时间戳交错它们:
messages_in = some_user.messages_received.where(:message_sender => selected_correspondent)
messages_out = some_user.messages_sent.where(:message_recipient => selected_correspondent).
我不喜欢这个解决方案,因为它涉及使用"where"查询多次点击Messages集合以及发送和接收的大量手动过滤和交错消息.努力.
在对话文档中嵌入消息.我将在下面提供用户,消息和对话的代码.会话通过has_and_belongs_to_many(nn,因为用户也可能有很多对话)链接到两个或多个用户.这也可能允许多用户对话.
我喜欢这个解决方案,因为为了向用户显示他的收件箱,我可以使用在Conversation文档中存储和更新的some_user.conversations顺序:last_message_received,不需要过滤.为了显示特定的对话,我不需要交错发送和接收的消息,因为消息已经以正确的顺序嵌入到对话文档中.
此解决方案的唯一问题是当您要添加消息时,找到由两个(或更多)用户共享的正确对话文档.这里建议一个解决方案:mongodb会话系统,但我不喜欢它,因为查询似乎相对昂贵,并且多用户对话的扩展看起来会变得棘手.相反,我在Conversation文档中有一个字段,该字段:lookup_hash是根据参与对话的每个用户的Object ID计算的SHA1哈希.这样,给定两个或更多用户,找到相应的对话文档(或者如果它还不存在则创建它)是微不足道的.
要向对话添加消息,我只使用Conversation.add_message(类方法,而非实例方法,因为对话可能尚不存在),为其提供发件人,收件人和新邮件对象.
我的问题是:考虑到Mongoid(或者一般只是NoSQL)架构设计最佳实践,我做了什么显然是错误的吗?我有什么办法可以改善我的解决方案吗?我使用哈希来查找对话的想法是个坏主意吗?
user.rb
class User
include Mongoid::Document
field :username, type: String
field :joined, type: DateTime, default: ->{ Time.now }
field :last_activity, type: DateTime, default: -> { Time.now }
has_and_belongs_to_many :conversations
end
Run Code Online (Sandbox Code Playgroud)
conversation.rb
require 'digest/sha1'
class Conversation
include Mongoid::Document
field :lookup_hash, type: String
field :created, type: DateTime, default: -> { Time.now }
field :last_message_time, type: DateTime, default: -> { Time.now }
# Array of user ids of users that have read all messages in this conversation
field :last_message_seen_by, type: Array, default: []
embeds_many :messages
has_and_belongs_to_many :participants, :class_name => 'User'
validates_presence_of :lookup_hash
index({ lookup_hash: 1 }, { unique: true, name: "lookup_hash_index" })
# Used to show a user a list of conversations ordered by last_message_time
index({ _id: 1, last_message_time: -1 }, { unique: true, name: "id_last_message_time_index" })
def self.add_message(recipient, sender, message)
# Find or create a conversation:
conversation = Conversation.find_or_create_by(
:lookup_hash => get_lookup_hash([recipient.id, sender.id])) do |c|
c.participants.concat [recipient, sender]
end
conversation.messages << message
conversation.last_message_time = Time.now
conversation.last_message_seen_by.delete(recipient)
conversation.save
end
private
def self.get_lookup_hash(participant_ids)
lookup_key = participant_ids.sort.join(':')
Digest::SHA1.hexdigest lookup_key
end
end
Run Code Online (Sandbox Code Playgroud)
message.rb
class Message
include Mongoid::Document
field :created, type: DateTime, default: -> { Time.now }
field :text, type: String
embedded_in :conversation
belongs_to :author, :class_name => 'User'
validates_length_of :text, minimum: 2, maximum: 256
validates_presence_of :author
end
Run Code Online (Sandbox Code Playgroud)
我猜你正在使用 MongoId 3.0。我在您的第一个解决方案中没有看到任何问题:
messages_in = some_user.messages_received.where(:message_sender => current_user)
messages_out = some_user.messages_sent.where(:message_recipient => current_user).
Run Code Online (Sandbox Code Playgroud)
您可以找到各种示例:
https://groups.google.com/forum/?fromgroups=#!topic/mongoid/BOBqhYLb7O0
我在几个带有 MongoId 的项目上有一个内部消息系统,并使用第一个解决方案。
如果添加其他类,"Conversation"则不应嵌入消息,因为一个对话可以包含无限数量的消息。你应该使用has_may messages和belongs_to conversation。
我认为这两种解决方案都很好,因此您可以根据您的项目逻辑选择您的需求。如果您的逻辑更简单,您可以选择第一种解决方案。否则,如果您的逻辑更复杂,请选择后一种解决方案。
问候!
| 归档时间: |
|
| 查看次数: |
1421 次 |
| 最近记录: |