読者です 読者をやめる 読者になる 読者になる

Shoken Startup Blog

KitchHikeを作っています。ひとつずつアウトプットします。

MongoDBへ様々なデータ型を保存/取得してみる。オブジェクトマッピング編

MongoDB Ruby

MongoDBへBoolean、バイナリ(BINARY)、Date、Timestamp、などをinsertして保存/取得する方法を紹介します。

サンプルコードはRubyを使いますが、便利なORMであるMongoidはあえて使わずに、プリミティブなドライバであるmongo-ruby-driverで実装してよりMongo Shellに近い操作を確認していきたいと思います。

今回は、そもそもMongoDBのデータ型(type)がRubyのオブジェクトにどのようにマッピングされるかを見てみます。


mongo-ruby-driverをgemからインストールしておいてください。

gem install mongo

環境

OS CentOS 5.4
ruby 1.9.3
gem 1.8.21
mongo 1.6.1
MongoDB 2.0.4

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はサポートしていないだとかもわかります。

まとめ

ドライバのソースを見てみると、いろいろわかる。


次回から、実際のデータ型を扱っていきます。