在MongoDB中存储数据的有效方法:嵌入式文档与单个文档 [英] Efficient way to store data in MongoDB: embedded documents vs individual documents

查看:56
本文介绍了在MongoDB中存储数据的有效方法:嵌入式文档与单个文档的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I store user activity data: when user visited current article, topic or personal message to show him how many new comments and messages were added while he was offline.

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

在这种情况下,我为每个文档存储一条记录.

In this case I store one record per document.

另一种选择是使用嵌入式文档,因此所有用户活动都将存储在一个文档中:

Another option is to use embedded documents, so all user activities will be stored in one document:

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并通过嵌入的文档找到我需要的活动.

So now I don't need to search through all SiteActivities (many many records) but I can fetch one user_activity for current_user and find activity I need through it embedded documents.

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

我的普通用例是:

我有一个用户和一个帖子,所以我正在使用此数据获取site_activity,以查看该用户上次访问帖子的日期.

I have got a user and a post so I am fetching for site_activity with this data to see the date when this user visited post last time.

第一个选择是

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中支持上限集合,我想这将在本周末发布.)

It would be better to use the first approach(individual documents) and use a capped collection if possible, as you don't want to have rapidly growing collection(mongoid will have support for capped collections in 2.2, which would be out this weekend I guess).

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

The second approach(embedded documents), you will need to first fetch the root document for the user and then traverse the array in application to find the activity related with post you are looking for. Mongoid may make it look like everything is done in db due to similarity of syntax in finding an embedded document, but its really iterating the array.

由于在进行查询之前已经具有user_id,activity_id和activity_type,并且您不希望在查找特定活动时从db中检索用户的整个活动列表,因此我更倾向于第一种情况.应用程序中的计算(搜索)量将大大减少,网络流量也会大大减少.

As you already have the user_id, activity_id and activity_type before making a query, and you would not want the whole list of activities for the user to be retrieved from db when you are looking for a particular activity, I will prefer first case. There would be much less calculations(searching) in application and there will be much less network traffic.

使用单个文档的方法,如果您还要在user_id,activity_id,activity_type上创建唯一索引,那就太好了.这将帮助您包含文档数量.您可以进行唯一性验证(额外查询),但是如果您具有唯一索引,则几乎没有必要.验证的唯一好处是,如果存在重复项,则会出现一个验证错误,但是除非您坚持安全模式,否则索引将无提示地忽略重复项.

With individual documents approach, it would be great if you also create a unique index on user_id, activity_id, activity_type. It will help you contain the number of documents. You can have the uniqueness validation(extra query), but that would be mostly unnecessary if you have the unique index. The only benefit of validation will be an validation error if there are duplicates, but index will ignore duplicate entries silently unless you persist in safe mode.

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

In case you also want the historical site activity to be persisted, you can have the structure like:

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中存储数据的有效方法:嵌入式文档与单个文档的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆