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

Ruby on rails 在MongoDB中存储数据的有效方法:嵌入式文档与单个文档,ruby-on-rails,ruby,performance,mongodb,mongoid,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 S

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

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(许多记录),但我可以为当前用户获取一个
user\u activity
,并通过嵌入的文档找到我需要的活动

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

我的普通用例是:

我有一个用户和一篇文章,所以我正在获取带有此数据的site_活动,以查看此用户上次访问文章的日期

我的第一个选择是:

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中支持封顶集合,我想这将在本周末推出)

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

由于在进行查询之前,您已经有了user\u id、activity\u id和activity\u type,并且在查找特定活动时,您不希望从db检索用户的整个活动列表,因此我更喜欢第一种情况。应用程序中的计算(搜索)会少得多,网络流量也会少得多

使用单个文档的方法,如果您还可以在用户id、活动id和活动类型上创建一个唯一的索引,那就太好了。它将帮助您包含文档的数量。您可以进行唯一性验证(额外的查询),但如果您有唯一索引,那么这将是不必要的。如果存在重复项,验证的唯一好处是验证错误,但除非您坚持使用安全模式,否则索引将自动忽略重复项

如果您还希望保留历史遗址活动,则可以采用如下结构:

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
类站点活动
include Mongoid::Document
包含Mongoid::时间戳
属于:用户
属于:活动,多态性:true
索引[:user\u id,:activity\u id,:activity\u type],:background=>true,:unique=>true
字段:上次访问时间,:type=>time
#上次访问时间仅用于历史记录,未使用
字段:上次访问次数,:type=>Array,:default=>[]
结束
activity=SiteActivity.find_或_initialize_by(:user_id=>current_user.id,
:activity\u id=>post.id,:activity\u type=>post.class)
时间=time.now.utc
activity.last\u access\u time=时间

activity.last_access_times昨天似乎讨论过类似的话题。
看看,也许会有帮助。

谢谢。这看起来像是你说服了我:)在我的例子中,我使用
Mongoid::Timestamps
作为最后一次访问时间来进行extracet
updated\u at
因为这是相同的东西是的,它的行为应该类似。