【问题标题】:Efficient way to store data in MongoDB: embedded documents vs individual documents在 MongoDB 中存储数据的有效方法:嵌入式文档与单个文档
【发布时间】:2011-08-24 10:02:11
【问题描述】:

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

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)

【问题讨论】:

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


    【解决方案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
    

    【讨论】:

    • 谢谢。看起来你已经说服了我:)
    • 就我而言,我使用Mongoid::Timestamps 提取updated_at 作为last_access_time,只要这是相同的东西
    • 是的,它的行为应该类似。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2011-02-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-11
      • 2015-06-20
      • 2020-11-22
      相关资源
      最近更新 更多