初めての MongoDB

MongoDB が気になったのでちょっと試してみた。なぜ MongoDB が気になったのかというと、Heroku の Add-ons で MongoHQ が使えるということなので。
Heroku 上で動作させることを前提としているので、言語は Ruby を使用。http://www.mongodb.org/display/DOCS/Object+Mappers+for+Ruby+and+MongoDB にOマッパー*1のリストがある。MongoRecord というのが MongoDB の開発元(?) である 10gen が開発しているようなので、それを使ってみることにした。

環境

  • OS:Ubuntu 9.10
  • Ruby:1.8.7
    • gems
      • mongo:1.0.1
      • mongo_record:0.5

インスートル

...忘れた。パッケージで入れたのは覚えてる。

レコードの作成と検索

コード
require 'rubygems'
require 'mongo'
require 'mongo_record'

class User < MongoRecord::Base
  collection_name :users
  fields :name, :age, :sex
  #index :name                  # なぜかエラーになるのでコメント
  def to_s
    "name:[#{name}], age:[#{age}], sex:[#{sex}]"
  end
end

MongoRecord::Base.connection = Mongo::Connection.new.db('mydb')

#---- 作成
users = []
users << User.new(:name => 'foo',  :age => 16,  :sex => :male)
users << User.new(:name => 'foo',  :age => 32,  :sex => :female)
users << User.new(:name => 'bar',  :age => 64,  :sex => :female)
users << User.new(:name => 'hoge', :age => 128, :sex => :male)
users.each {|u| u.save}

#---- 検索
puts '---- all'
User.find(:all).each {|u| puts u.to_s}
puts '---- name = "foo"'
User.find(:all, :conditions => ['name = ?', 'foo']).each {|u| puts u.to_s}
puts '---- name = "foo" and age < 32'
User.find(:all, :conditions => ['name = ? and age < ?', 'foo', 32]).each {|u| puts u.to_s}
puts '---- select'
puts User.find(:last, :select => [:name, :age]).to_s
puts '---- not found :by all'
p User.find(:all, :conditions => ['name = ?', 'pero'])
puts '---- not found by :last'
users.each {|u| u.delete}
p User.find(:last)
結果
---- all
name:[foo], age:[16], sex:[male]
name:[foo], age:[32], sex:[female]
name:[bar], age:[64], sex:[female]
name:[hoge], age:[128], sex:[male]
---- name = "foo"
name:[foo], age:[16], sex:[male]
name:[foo], age:[32], sex:[female]
---- name = "foo" and age < 32
name:[foo], age:[16], sex:[male]
---- select
name:[hoge], age:[128], sex:[]
---- not found :by all
#<Mongo::Cursor:0xb74469a40 ...> # 長いので省略
---- not found by :last
nil
  • find の第一引数には id, :all, :first, :last を指定する。
  • :all と :first, :last で返ってくるオブジェクトが違う。:all だと Mongo::Cursor が返ってくるけど、:first, :last の場合は User オブジェクトが返ってくる。統一されていた方がいいような。...そうでもないか、あらかじめ多くて 1 件しかレコードが返ってこないことはわかってるから。
  • 条件文に "?" をプレースホルダとして使ったけど、(No)SQLインジェクション対策はされるのだろうか?
  • そもそも、どうなるとインジェクションされるのだろう*2
  • いろいろな NoSQL サーバがあるけど、脆弱性対策をなくすためこれをしとけっていうのは各サーバごとに異なる?
  • save メソッドは commit とは違うものだった。delete したあとで save を実行するとレコードが再度書き込まれた...orz。
# save しないと DB には反映されないだろうと思っていたが、そんなことはなかった。
# ↓消して書き込んでいるので無意味な処理。
users.each {|u| u.delete; u.save }

*1:RDBじゃなから R(elational) がない?

*2:「インジェクションされる」っていう使い方はあり?