2011-12-15
Mongoidノート - validates_uniqueness_of で :case_sensitive => false を指定すると……
Mongoid の validates_uniqueness_of で :case_sensitive => false を指定するとインデックスが使われないような予感がしたので、確認のためソースを追ってみた。
# File: mongoid-2.3.4/lib/mongoid/validations.rb def validates_uniqueness_of(*args) validates_with(UniquenessValidator, _merge_attributes(args)) end
UniquenessValidator の方を見てみる。
# File: mongoid-2.3.4/lib/mongoid/validations/uniqueness.rb def validate_each(document, attribute, value) if document.embedded? # snip else criteria = klass.where(criterion(document, attribute, value)) criteria = scope(criteria, document, attribute) document.errors.add(attribute, :taken) if criteria.exists? end end
if criteria.exists? ならエラーと。
# File: mongoid-2.3.4/lib/mongoid/validations/uniqueness.rb def criterion(document, attribute, value) { attribute => filter(value) }.tap do |selector| if document.persisted? || (document.embedded? && (document.primary_key != Array.wrap(attribute))) selector.merge!(:_id => { "$ne" => document.id }) end end end
criterion は where に渡すハッシュを返すメソッドで
{ :name => "David_Thomas" }
みたいなのを返す。
で、:case_sensitive => false ならどうなるんだ?
# File: mongoid-2.3.4/lib/mongoid/validations/uniqueness.rb def filter(value) !case_sensitive? && value ? /^#{Regexp.escape(value.to_s)}$/i : value end
わわわ。正規表現になるのかよ。これだとインデックスが使えないはず。
For simple prefix queries (also called rooted regexps) like /^prefix/, the database will use an index when available and appropriate (much like most SQL databases that use indexes for a LIKE 'prefix%' expression). This only works if you don't have i (case-insensitivity) in the flags.
とあり、simple prefix queries (also called rooted regexps) like /^prefix/ のような場合を除きインデックスは使われない(使えない)ので、:case_sensitive => false を指定した場合、
validates_uniqueness_of は validation に際して、フィールドの値がユニークであることを保証するために、$regex を用いたクエリでコレクションの全ドキュメント(またはそのインデックス上のエントリ)をスキャンすることになる。*1
ということで注意が必要というか、validates_uniqueness_of を使うなら最初から大文字の使用を禁じるとか、大文字は小文字に変換した上で格納するなどして、インデックスを効かせられるようにしておくべき。
- 4 http://www.google.co.jp/url?sa=t&rct=j&q=vimfiler&source=web&cd=1&ved=0CDIQFjAA&url=http://d.hatena.ne.jp/h1mesuke/20100611/p1&ei=E67pTovrJamHmQXE_tSACg&usg=AFQjCNFpuJTU2kZsYV1RyhANT8JqrlHaLA&sig2=W_FwkBJrNkd8OJV-LNWvIw
- 3 http://atnd.org/events/21925
- 3 http://b.hatena.ne.jp/entry/d.hatena.ne.jp/h1mesuke/20100611/p1
- 2 http://www.google.co.jp/search?sourceid=navclient&hl=ja&ie=UTF-8&rlz=1T4GGLL_jaJP332JP332&q=pukiwiki+javascript
- 2 http://www.google.co.jp/url?sa=t&rct=j&q=unite+outline&source=web&cd=4&ved=0CDgQFjAD&url=http://d.hatena.ne.jp/h1mesuke/20101107/p1&ei=S-_pTvXHLu2hmQWgmuHvCQ&usg=AFQjCNHC3ixR2vjsUMpYaCruJCeXBdzFnw
- 1 http://d.hatena.ne.jp/thinca/
- 1 http://d.hatena.ne.jp/thinca/20111204/1322932585
- 1 http://reader.livedoor.com/reader/
- 1 http://search.yahoo.co.jp/search?ei=UTF-8&p=vimfiler
- 1 http://search.yahoo.co.jp/search?p=rails+session+確認方法&aq=-1&oq=&ei=UTF-8&fr=top_ga1_sa&x=wrt
