在mongoid范围链上执行方法

时间:2013-04-22 15:13:27

标签: ruby-on-rails activerecord model mongoid

我需要使用Rails和MongoId获取一些随机文档。由于我计划拥有非常大的集合,因此我决定在每个文档中放置一个“随机”字段,并使用该字段选择文档。我在模型中编写了以下方法:

def random(qty)
  if count <= qty
    all
  else
    collection = [ ]
    while collection.size < qty
      collection << where(:random_field.gt => rand).first
    end
    collection
  end
end

此功能实际上有效,集合中填充了 qty 随机元素。但是当我尝试使用它像这样的范围:

User.students.random(5)

我明白了:

undefined method `random' for #<Array:0x0000000bf78748>

如果我尝试将方法设为lambda范围,我会得到:

undefined method `to_criteria' for #<Array:0x0000000df824f8>

鉴于我对随机之后的任何其他范围不感兴趣,我如何在链中使用我的方法?

提前致谢。

1 个答案:

答案 0 :(得分:0)

我最终使用以下内容扩展了Mongoid :: Criteria类。不知道这是不是最好的选择。实际上我认为它很慢,因为它至少执行 qty 查询。

我不知道 not_in 是否可用于普通的ActiveRecord模块。但是,如果需要,您可以删除 not_in 部分。这只是减少查询数量的优化。

对于文件数量比qty多两倍(或更大)的集合,您应该具有完全 qty 查询。

module Mongoid
  class Criteria

    def random(qty)
      if count <= qty
        all
      else
        res = [ ]
        ids = [ ]
        while res.size < qty
          el = where(:random_field.gt => rand).not_in(id: ids).first

          unless el.nil?
            res << el
            ids << el._id
          end
        end
        res
      end
    end

  end
end

希望您觉得这很有用:)