我有一个带有嵌入式注释的List文档。在视图中,除了用户的评论,我还想显示他们的屏幕名和头像。头像可以更改,用户名也可以更改。
我想确定这里的设计最佳实践是什么。为了最好地利用Mongo,嵌入的注释看起来应该像这样:
评论模型
class Comment
include Mongoid::Document
field :user_id
field :username
field :profile_pic_url
field :content
field :created_at, type: Date
embedded_in :list, :inverse_of => :comments
end
风险在于,如果用户更改了评论数据(用户的屏幕名和个人资料图片),则评论数据(用户的屏幕名和个人资料图片)将变得过时,除非在user模型上有一个after_save过滤器,以便更新评论中的所有实例。
对正确的设计有什么指导吗?我可以让评论不被嵌入,让一个用户有很多评论,一个列表有很多评论,但我试图发挥Mongo的优势。
您的应用程序,它的访问模式、可伸缩性和性能需求胜过后端问题。使用SQL,规范化和链接/引用几乎是您唯一的选择,但使用MongoDB,您可以嵌入。
MongoDB提供了灵活的匹配模式,以满足您的应用程序的需求,您可以选择规范化/链接/引用或非规范化/嵌入根据需要,和Mongoid使它很容易选择。
(a)规范化减少冗余,遵循Don't Repeat Yourself (DRY)的良好原则。(b)反规范化引入冗余,遵循常见的做法,如缓存或记忆的性能。
一般根据您的应用程序的需要:
要求高一致性-是:normalize/link,否:dennormalize/embed
高读性能要求-是:dennormalize/embed,否:normalize/link
高写性能要求- yes: normalize/link, no: dennormalize/embed
需要高缩放-是:normalize/link,否:dennormalize/embed
关系:
一对一-是:反规范化/嵌入,否:…
一对多- yes: normalize/embed, no:…
多对多- yes: normalize/link, no:…
有各种处理一致性的技术,例如,后台或夜间进程用于最终一致性,备用缓存用于立即一致性,等等。
坏消息是,没有不需要思考的公式。好消息是MongoDB具有匹配您的应用程序的灵活性。10gen提供Schema Design讲座
我会引用一个用户,而不是在每个评论中放置每个字段。
class User
include Mongoid::Document
include Mongoid::Timestamps
field :user_id
field :username
field :profile_pic_url
has_many :comments
end
class Comment
include Mongoid::Document
include Mongoid::Timestamps
field :content
belongs_to :user
embedded_in :list, :inverse_of => :comments
end
您可以在http://mongoid.org/en/mongoid/docs/relations.html#has_many
找到关于has_many关系的文档我还使用了额外的时间戳,并删除了记录在http://mongoid.org/en/mongoid/docs/extras.html#timestamps上的created_at字段。