在MongoDB中存储数据的有效方法:嵌入式文档vs单个文档



我存储用户活动数据:当用户访问当前文章,主题或个人消息时,向他显示在他离线时添加了多少新评论和消息。

class SiteActivity
  include Mongoid::Document
  include Mongoid::Timestamps
  belongs_to :user
  belons_to :activity, polymorphic: true
end

在本例中,我为每个文档存储一条记录。

另一个选择是使用嵌入式文档,这样所有的用户活动将被存储在一个文档中:

class SiteActivity
  include Mongoid::Document
  belongs_to :user
  embeds_many :user_activities
  validates :user_id, uniqueness: true
end
class UserActivity
  include Mongoid::Document
  include Mongoid::Timestamps
  embedded_in :site_activity
  belongs_to :activity, polymorphic: true
end

所以现在我不需要搜索所有的SiteActivities(许多许多记录),但我可以为current_user获取一个user_activity,并找到我需要通过它嵌入文档的活动。

哪种方式更有效地存储和搜索数据?

我的普通用例是:

我有一个用户和一个帖子,所以我用这个数据获取site_activity,以查看这个用户上次访问帖子的日期。

与我的第一个选项:

activity = SiteActivity.where(user_id: current_user.id, activity_id: post.id, activity_type: post.class)
与第二个

user_activity = SiteActivity.where(user_id: current_user.id)
activity = user_activity.user_activities.where(activity_id: post.id, activity_type: post.class)

如果可能的话,最好使用第一种方法(单独的文档)并使用有上限的集合,因为您不希望有快速增长的集合(mongoid将在2.2中支持有上限的集合,我猜将在本周末发布)。

第二种方法(嵌入文档),您需要首先为用户获取根文档,然后遍历应用程序中的数组以查找与您正在查找的post相关的活动。由于查找嵌入式文档的语法相似,Mongoid可能使它看起来像是在db中完成的,但它实际上是在迭代数组。

在进行查询之前,您已经拥有user_id, activity_id和activity_type,并且您不希望在寻找特定活动时从db检索用户的整个活动列表,我更喜欢第一种情况。这将大大减少应用程序的计算(搜索),也将大大减少网络流量。

使用独立文档方法,如果您还在user_id, activity_id, activity_type上创建唯一索引,那将是非常好的。它将帮助你控制文件的数量。您可以进行唯一性验证(额外的查询),但如果您有惟一索引,那么就没有必要这样做了。验证的唯一好处是如果存在重复项会出现验证错误,但是index将静默地忽略重复项,除非您以安全模式持久化。

如果您还希望持久化历史站点活动,您可以使用如下结构:

class SiteActivity
  include Mongoid::Document
  include Mongoid::Timestamps
  belongs_to :user
  belongs_to :activity, polymorphic: true
  index [:user_id, :activity_id, :activity_type], :background => true, :unique => true
  field :last_access_time, :type => Time
  # last_access_times just here for history, not used
  field :last_access_times, :type => Array, :default => []
end
activity = SiteActivity.find_or_initialize_by(:user_id => current_user.id,
               :activity_id => post.id, :activity_type => post.class)
time = Time.now.utc
activity.last_access_time = time
activity.last_access_times << time
activity.save

似乎昨天也讨论过类似的话题。看看mongodb中日志分析数据库的最佳模式设计,也许它会有所帮助。

最新更新