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

时间:2011-08-24 10:02:12

标签: ruby-on-rails ruby performance mongodb mongoid

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

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)

2 个答案:

答案 0 :(得分:1)

最好使用第一种方法(单个文档)并尽可能使用上限集合,因为您不希望快速增长的集合(mongoid将支持2.2中的上限集合,这将是这个周末我想)。

第二种方法(嵌入式文档),您需要先为用户获取根文档,然后遍历应用程序中的数组,以查找与您要查找的帖子相关的活动。由于查找嵌入式文档时语法的相似性,Mongoid可能会让所有内容都在db中完成,但它实际上是在迭代数组。

由于您在进行查询之前已经拥有了user_id,activity_id和activity_type,并且您不希望在查找特定活动时从db中检索用户的整个活动列表,我将首选案例。应用程序中的计算(搜索)要少得多,网络流量也会少得多。

使用单个文档方法,如果您还在user_id,activity_id,activity_type上创建唯一索引,那将会很棒。它将帮助您包含文档数量。您可以进行唯一性验证(额外查询),但如果您拥有唯一索引,那么这几乎是不必要的。如果存在重复,验证的唯一好处是验证错误,但索引将静默忽略重复条目,除非您保持安全模式。

如果您还希望保留历史网站活动,则可以使用以下结构:

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

答案 1 :(得分:1)

似乎昨天讨论了类似的话题。 看看best possible schema design for log analysis database in mongodb也许会有所帮助。