MongoDB 给 Mongoid 加上 find_by_xxx 方法

iwinux · 2011年11月21日 · 最后由 iwinux 回复于 2012年06月03日 · 5825 次阅读

刚开始用 Mongoid 的时候就发现它不支持 ActiveRecord 里的 find_by_xxx 方法,忍了好久,终于忍无可忍,在 Github 找到一段代码,稍微改写了一下,把这个问题解决了。把这个文件存进 config/initializers/ 里就可以用了。

https://gist.github.com/1381824

module Mongoid
  module Finders
    # add find_by_xxx to Mongoid
    # from https://github.com/mitijain123/mongoid/commit/b28b360b787ba4cd32e5423afcfa3b83574f9df1
    def method_missing(method_id, *args, &block)
      conditions = {}
      bang = false

      case method_id.to_s
      when /^find_(all|last||first)_?by_([_a-zA-Z]\w*)(!?)$/
        finder_type = $1.blank? ? :first : $1.to_sym
        bang = true if $3 == '!'

        $2.split(/_and_/).each_with_index do |attr, i|
          conditions[attr] = args[i]
        end

        result = find(finder_type, :conditions => conditions)

        if result.nil? and bang
          raise Mongoid::Errors::DocumentNotFound.new(self.class, args)
        else
          return result
        end
      else
        nil
      end
    end
  end
end

用了多久了?靠谱么?之前只是自己加了个 find_by_id 的方法

ORM 支持 where 这样的查询之后 find by xx 这种的 api 很鸡肋 User.where(:id => 1).first User.find_by_id(1) 我感觉没什么区别

当然如果是支持 find_or_create_by_oo_and_xx 这样的 API 还是比较不错的。

#2 楼 @hooopo find_by_id 还是需要搞一个的,因为 Model.find 如果没有会出 DocumentNotFound 的异常,需要写个 find_by_id 的方法来不抛出异常

#2 楼 @hooopo #3 楼 @huacnlee 我是反过来需要一个 find_by_number! 抛异常

def find_by_id(*args)
  find(*args) rescue nil
end

好像这样就可以

#5 楼 @hooopo 我是这样写的

def find_by_id(id)
  where(:_id => id).first
end

AR 好像支持 find_by_number! 抛异常

@hooopo 主要是 ActiveRecord 里用习惯了。其实今天是被迫写这个东西的,因为我用的 oauth-plugin 这个 gem 用了一堆 find_by_xxx 方法,完全没考虑与 Mongoid 兼容,一个个改太蛋疼了,索性给 Mongoid 加上这些方法算了 =。=

我记得看到过 mongoid 的作者说不加 find_by_XXX 方法是为了更好的性能。其实直接用 Model.where(:xxx => yyy).first 类似的也没啥。

#9 楼 @anylei 性能不好是一回事,但明明支持起来很简单(而且人家都写好了 pull request 进来了)他却不支持……

#10 楼 @iwinux 其实有时候觉得 find_by_... 写起来别扭得很

#6 楼 @huacnleewhere(:_id => id).find(:first)比较过,where(:_id => id)[0]会提升一些性能。没试过where(:_id => id).first`,回家试试。

相对于 find_by_xxx,更喜欢直接 where 另外,lz 这样的 monkey patch 并不太好,最好保证 mongoid 版本的稳定性。如果 mongoid 的代码改了,容易出问题。

method_missing 很慢的。

这个实现确实不如 ActiveRecord 里面那个,AR 的实现是第一次使用这个方法的时候用 define_method 生成一个,以后就是普通方法调用了。

关于 mongoid 能够使用的内置方法都在什么地方可以查询到啊,ActiveRecored 的方法又不能完全使用,但是不知道哪些可以使用,哪些不可以,查询官方文档的时候还没有搜索功能……

#16 楼 @cloudaice 对于这些 Ruby gems,很多时候直接读源码比较快 = =

需要 登录 后方可回复, 如果你还没有账号请 注册新账号