MongoDBへ様々なデータ型を保存/取得してみる。オブジェクトマッピング編
MongoDBへBoolean、バイナリ(BINARY)、Date、Timestamp、などをinsertして保存/取得する方法を紹介します。
サンプルコードはRubyを使いますが、便利なORMであるMongoidはあえて使わずに、プリミティブなドライバであるmongo-ruby-driverで実装してよりMongo Shellに近い操作を確認していきたいと思います。
今回は、そもそもMongoDBのデータ型(type)がRubyのオブジェクトにどのようにマッピングされるかを見てみます。
mongo-ruby-driverをgemからインストールしておいてください。
gem install mongo
MongoDBのデータ型
まずは、MongoDBのデータ型の一覧です。
このページの中ほどにあります。
高度なクエリー - Docs-Japanese - 10gen Confluence
Type Name Type Number Double 1 String 2 Object 3 Array 4 Binary data 5 Object id 7 Boolean 8 Date 9 Null 10 Regular expression 11 JavaScript code 13 Symbol 14 JavaScript code with scope 15 32-bit integer 16 Timestamp 17 64-bit integer 18 Min key 255 Max key 127
Type Numberを指定して検索することで、そのデータ型が保存されているかを確認しています。
具体的にはこういうクエリになります。
[root@xxx ~]# mongo MongoDB shell version: 2.0.4 connecting to: test > db.boolean_test.insert({x:true}) #Boolean型としてinsert > db.boolean_test.insert({x:'true'}) #String型としてinsert > db.boolean_test.find({x:{$type:8}}) #key=xのvalueがBoolean型のものがヒット { "_id" : ObjectId("4f8541e908b824ae767885e0"), "x" : true } > db.boolean_test.find({x:{$type:2}}) #key=xのvalueがString型のものがヒット { "_id" : ObjectId("4f856a3b327004268a795433"), "x" : "true" }
また、typeof()でデータ型を確認できます。
> typeof(true) boolean > typeof(false) boolean > typeof(Boolean(1)) # =>true,Boolean(0)以外ならtrue boolean > typeof(Boolean(0)) # =>false boolean > typeof('true') string
Rubyへのマッピング
次に、Rubyへの型変換、つまりデータ型のマッピングがどのような実装になっているかソースを見てみます。
/usr/local/lib/ruby/gems/1.9.1/gems/bson-1.6.1/lib/bson/bson_ruby.rb
のbson_type(o)がそれっぽい。
def bson_type(o) case o when nil NULL when Integer NUMBER_INT when Float NUMBER when ByteBuffer BINARY when Code CODE_W_SCOPE when String STRING when Array ARRAY when Regexp REGEX when ObjectId OID when DBRef REF when true, false BOOLEAN when Time DATE when Hash OBJECT when Symbol SYMBOL when MaxKey MAXKEY when MinKey MINKEY when Timestamp TIMESTAMP when Numeric raise InvalidDocument, "Cannot serialize the Numeric type #{o.class} as BSON; only Fixum, Bignum, and Float are supported." when Date, DateTime raise InvalidDocument, "#{o.class} is not currently supported; " + "use a UTC Time instance instead." else if defined?(ActiveSupport::TimeWithZone) && o.is_a?(ActiveSupport::TimeWithZone) raise InvalidDocument, "ActiveSupport::TimeWithZone is not currently supported; " + "use a UTC Time instance instead." else raise InvalidDocument, "Cannot serialize #{o.class} as a BSON type; it either isn't supported or won't translate to BSON." end end end
引数にはRubyのオブジェクトを取ります。
ソースを見ると、RubyのTimeクラスはMongoDBのDATE型に、などというマッピングがわかります。
また、Numericクラスは使えないからFixumかBignumかFloatを使えだとか、Date/DateTimeはサポートしていないだとかもわかります。
まとめ
ドライバのソースを見てみると、いろいろわかる。
次回から、実際のデータ型を扱っていきます。