Эффективный способ хранения данных в MongoDB: встроенные документы против отдельных документов - PullRequest
2 голосов
/ 24 августа 2011

Я храню данные об активности пользователя: когда пользователь посещал текущую статью, тему или личное сообщение, чтобы показать ему, сколько новых комментариев и сообщений было добавлено, когда он был в автономном режиме.

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_activity для current_user и найти нужную мне активность с помощью встроенных документов.

Какой способ более эффективен для хранения и поиска данных?

Мой обычный вариант использования:

У меня есть пользователь и сообщение, поэтому я выбираю 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 ]

1 голос
/ 24 августа 2011

Похоже, что аналогичная тема обсуждалась вчера. Посмотрите на наилучший возможный дизайн схемы для базы данных анализа журналов в mongodb Возможно, это поможет.

1 голос
/ 24 августа 2011

Было бы лучше использовать первый подход (отдельные документы) и использовать ограниченную коллекцию, если это возможно, так как вы не хотите иметь быстро растущую коллекцию (mongoid будет иметь поддержку ограниченных коллекций в версии 2.2, которая будет отсутствовать в эти выходные я думаю).

При втором подходе (внедренные документы) вам необходимо сначала получить корневой документ для пользователя, а затем просмотреть массив в приложении, чтобы найти действие, связанное с публикацией, которую вы ищете. Mongoid может заставить его выглядеть так, как будто все делается в БД, из-за сходства синтаксиса при поиске внедренного документа, но на самом деле он повторяет массив.

Поскольку у вас уже есть user_id, activity_id и activity_type до выполнения запроса, и вы не хотите, чтобы весь список действий для пользователя был извлечен из базы данных, когда вы ищете конкретное действие, я предпочту первый случай , В приложении будет намного меньше вычислений (поиска) и будет намного меньше сетевого трафика.

При подходе к отдельным документам было бы замечательно, если бы вы также создали уникальный индекс для 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
...