0

我目前在 Rails 应用程序中有以下控制器方法:

def index
  @entries = []
  @entries << QuickPost.where(:user_id.in => current_user.followees.map(&:ff_id) << current_user.id)
  @entries << Infographic.where(:user_id.in => current_user.followees.map(&:ff_id) << current_user.id)
  @entries.flatten!.sort!{ |a,b| b.created_at <=> a.created_at }

  @entries = Kaminari.paginate_array(@entries).page(params[:page]).per(10)
end

我意识到这非常低效,所以我正在寻找一种更好的方法来实现相同的目标,但我是 MongoDB 的新手,想知道最好的解决方案是什么。

有没有办法在 MongoDB 中跨两个集合进行排序的 limit() 查询或 MapReduce 函数?我猜没有,但在这种情况下肯定会节省很多精力!

我目前在想我有两个选择:

  1. 创建一个主 'StreamEntry' 类型模型,并让 Infographic 和 QuickPost 都继承自该模型,以便将两种数据类型存储在同一个集合中。这个问题是我有现有数据,我不知道如何将它从旧集合移动到新集合。
  2. 使用 Streama (https://github.com/christospappas/streama) 之类的东西创建一个单独的 Stream/ActivityStream 模型。我在这里看到的问题是,它需要大量的前期工作,并且由于隐私设置和项目的编辑/删除,流需要经常重建。

有没有我忽略的选项?我是否过度设计了上述选项?对于这种情况,有哪些最佳实践?

任何信息将不胜感激,到目前为止我真的很喜欢 MongoDB,并希望避免在未来陷入这样的陷阱。谢谢。

4

1 回答 1

2

继承解决方案很好,但是当继承的模型很接近时。例如 :

class Post < BasePost
  field :body, type: String
end
class QuickPost < BasePost
end
class BasePost
  field :title, type: String
  field :created_at, type: Time
end

但是当模型增长或差异太大时,您的第二个解决方案会更好。

class Activity
  include Mongoid::Document

  paginates_per 20

  field :occurred_at, :type => Time, :default => nil
  validates_presence_of :occurred_at

  belongs_to :user
  belongs_to :quick_post
  belongs_to :infographic

  default_scope desc(:occurred_at)
end

例如:

class QuickPost
  include Mongoid::Document
  has_one :activity, :dependent => :destroy
end

依赖销毁使活动在 QuickPost 被销毁时被销毁。您可以使用 has_many 并进行调整。

要创建活动,您可以创建一个观察者:

class ActivityObserver < Mongoid::Observer
  observe :quick_post, :infographic

  def after_save(record)
    if record.is_a? QuickPost
      if record.new_record?
        activity = record.build_activity
        activity.user = record.user
        # stuff when it is new
      else
        activity = record.activity
      end
      activity.occurred_at = record.occurred_at
      # common stuff
      activity.save
    end
  end
end
于 2012-06-08T08:32:42.157 回答