MongoDBへ様々なデータ型を保存/取得してみる。バイナリ(BINARY)編
MongoDBへ様々なデータ型を保存/取得してみる。オブジェクトマッピング編 - オープンソースよしみ視点
の続きです。
MongoDBへバイナリ(BINARY)、Boolean、Date、Timestamp、などをinsertして保存/取得する方法を紹介します。
サンプルコードはRubyを使いますが、便利なORMであるMongoidはあえて使わずに、プリミティブなドライバであるmongo-ruby-driverで実装してよりMongo Shellに近い操作を確認していきたいと思います。
今回はMongoDBのバイナリデータ保存/取得に関して書きます。
バイナリ(BINARY)型
Mongo ShellでBINARY型を扱うことは稀だと思いますので省略して、Rubyでの操作から入ります。
BINARY型をRubyで扱う上での注意点
■保存・・・BSON::Binaryクラスのインスタンスとしてinsert
■取得・・・to_sメソッドで文字列として扱う
バイナリ(BINARY)型をinsertする
Gmailから添付ファイルを取得して、MongoDBに画像データをバイナリで保存します。
下のソースコード中に出てくる## 省略 Gmailから添付ファイルを取得する処理 ##はruby-gmailを使ってRubyからGmailの添付ファイルを取得 - オープンソースよしみ視点を参考にしてください。
require 'mongo' db_name='test' # MongoDBのデータベース名 coll_name='image_test_ruby' # MongoDBのコレクション名 ## 接続処理 db = Mongo::Connection.new.db(db_name) coll = db.collection(coll_name) ## 省略 Gmailから添付ファイルを取得する処理 ## if (attachment.content_type.start_with?('image/')) filename = attachment.filename image = attachment.body.decoded coll.insert({:filename => filename, :image => BSON::Binary.new(image.to_blob, BSON::Binary::SUBTYPE_BYTES) }) end db.connection.close
Binaryクラスのコンストラクタは2つ引数があります。
第一引数はバイナリデータ、第二引数はSUBTYPEと呼ばれるものです。
SUBTYPEはbinary.rbで以下のように定義されています。
私の環境ではここにありました。
/usr/local/lib/ruby/gems/1.9.1/gems/bson-1.6.1/lib/bson/types/binary.rb
require 'bson/byte_buffer' class Binary < ByteBuffer SUBTYPE_SIMPLE = 0x00 SUBTYPE_BYTES = 0x02 SUBTYPE_UUID = 0x03 SUBTYPE_MD5 = 0x05 SUBTYPE_USER_DEFINED = 0x80 # One of the SUBTYPE_* constants. Default is SUBTYPE_BYTES. attr_accessor :subtype # Create a buffer for storing binary data in MongoDB. # # @param [Array, String] data to story as BSON binary. If a string is given, the on # Ruby 1.9 it will be forced to the binary encoding. # @param [Fixnum] one of four values specifying a BSON binary subtype. Possible values are # SUBTYPE_BYTES, SUBTYPE_UUID, SUBTYPE_MD5, and SUBTYPE_USER_DEFINED. # # @see http://www.mongodb.org/display/DOCS/BSON#BSON-noteondatabinary BSON binary subtypes. def initialize(data=[], subtype=SUBTYPE_SIMPLE) super(data) @subtype = subtype end def inspect "<BSON::Binary:#{object_id}>" end end end
BYTESやUUIDやMD5など選択できるようですが、どのような違いがあるかはわからず。。
Mongo Shellから見たときに、BinDataの一つ目の値となるようです。
> db.image_test.findOne(); { "_id" : ObjectId("4f7827683e91d82eca000001"), "filename" : "画像データ", "image" : BinData(2,"(画像のバイナリデータ)") }
バイナリ(BINARY)型を画像データとして表示する
Rubyからの操作です。
ByteBufferオブジェクトが返ってくるので、to_sメソッドを使ってバイナリの文字列?にします。
参考
Class: BSON::ByteBuffer
— Documentation for bson (1.6.1)
これまた、プリミティブな動きを理解するためにCGIで動きを確認します。
Mongo DBからバイナリデータを取得して、画像を表示するCGIのサンプルです。
#!/usr/local/bin/ruby # -*- coding: utf-8 -*- ## ## Mongo DBからバイナリデータを取得して、画像を表示するCGI ## require 'mongo' db_name='test' # MongoDBのデータベース名 coll_name='image_test' # MongoDBのコレクション名 ## 接続処理 db = Mongo::Connection.new.db(db_name) coll = db.collection(coll_name) ## データを取得 doc = db[coll_name].find_one() image = doc['image'].to_s # doc['image'] => ByteBufferオブジェクトが返ってくる db.connection.close puts "Content-type: image/png;" puts "Content-length: #{image.size.to_s}" puts "" # ここに改行が必要 print image # 画像を表示 to_blobはいらない
おまけ
Hello Worldを表示するRubyのCGI
#!/usr/local/bin/ruby # -*- coding: utf-8 -*- puts "Content-type: text/html; charset=UTF-8" puts "" puts 'Hello World'