Rails で MongoDB を使ってみた

2010/03/23

Ubuntu Karmic (9.10) で MongoDB + mongoid を使って簡単な Rails アプリケーションを作ってみました。

MongoDB とは、最近注目を集めつつあるドキュメント指向データベースの一種。mongoid は MongoDB にアクセスするための RubyGems。

参考資料:

次の行を /etc/apt/sources.list の末尾に追加

deb http://downloads.mongodb.org/distros/ubuntu 9.10 10gen

aptitude で MongoDB をインストール。

% sudo aptitude update
% sudo aptitude mongodb-stable

Windows を含む他の OS でのインストール手順については、Quickstart - MongoDB をご覧ください。

動作確認。

% mongo
MongoDB shell version: 1.2.4
url: test
connecting to: test
type "help" for help
> db.foo.save( { a : 1 } )
> db.foo.find()
{ "_id" : ObjectId("4ba7859134532c5d5844387e"), "a" : 1 }
> exit
bye

mongod の停止と開始。

% sudo service mongodb stop
% sudo service mongodb start

ここからは、http://mongoid.org/docs/installation に従って、Rails アプリケーションをセットアップ。

gem で mongoid, mongo_ext をインストール。mongo_ext は高速化のための拡張ライブラリ。

% sudo gem install mongoid
% sudo gem install mongo_ext

新規アプリケーション papagena を作成。

% rails papagena
% cd papagena

config/environment.rb に次の行を追加(Rails::Initializer.run do |config| ... end の間に)。

  config.load_paths += %W( #{RAILS_ROOT}/app/documents )
  config.gem "mongoid", :lib => "mongoid", :version => "1.2.14"

config/database.mongo.yml

development:
  host: localhost
  database: papagena_dev

config/initializers/mongoid.rb

File.open(File.join(RAILS_ROOT, 'config/database.mongo.yml'), 'r') do |f|
  @settings = YAML.load(f)[RAILS_ENV]
end

Mongoid.configure do |config|
  name = @settings["database"]
  config.master = Mongo::Connection.new.db(name)
end

app/documents ディレクトリを作成。

% mkdir app/documents

app/documents/person.rb

class Person
  include Mongoid::Document
  field :first_name
  field :last_name

  def full_name
    "#{first_name} #{last_name}"
  end
end

public/index.html を削除。

% rm public/index.html

config/routes.rb

ActionController::Routing::Routes.draw do |map|
  map.root :controller => 'people'
  map.resources :people
end

app/controllers/people_controller.rb

class PeopleController < ApplicationController
  def index
    @people = Person.all
  end

  def show
    @person = Person.find(params[:id])
  end

  def new
    @person = Person.new
  end

  def edit
    @person = Person.find(params[:id])
  end

  def create
    @person = Person.new(params[:person])
    if @person.save
      redirect_to @person
    else
      render :action => 'new'
    end
  end

  def update
    @person = Person.find(params[:id])
    @person.attributes = params[:person]
    if @person.save
      redirect_to @person
    else
      render :action => 'edit'
    end
  end

  def destroy
    @person = Person.find(params[:id])
    @person.destroy
    redirect_to :people
  end
end

app/views/index.html.erb

<h1>People#index</h1>

<ul>
<% @people.each do |person| %>
  <li>
    <%= link_to h(person.full_name), person %>
    <%= link_to 'Edit', [ :edit, person ] %>
    <%= link_to 'Delete', person, :method => :delete %>
  </li>
<% end %>
</ul>

<%= link_to 'New person', [ :new, :person ] %>

app/views/show.html.erb

<h1>People#show</h1>

First Name: <%= @person.first_name %><br />
Last Name: <%= @person.last_name %><br />

<%= link_to 'List', :people %>

app/views/new.html.erb

<h1>People#new</h1>

<% form_for @person do |f| %>
<%= f.label :first_name %>
<%= f.text_field :first_name %><br />
<%= f.label :last_name %>
<%= f.text_field :last_name %><br />
<%= f.submit %>
<% end %>

app/views/edit.html.erb

<h1>People#edit</h1>

<% form_for @person do |f| %>
<%= f.label :first_name %>
<%= f.text_field :first_name %><br />
<%= f.label :last_name %>
<%= f.text_field :last_name %><br />
<%= f.submit %>
<% end %>

アプリケーションを起動。

 % ruby script/server

お、動いた!


気付いたこと。

  • データベースを create するという操作は不要。いきなり使える。
  • マイグレーションも不要。
  • オブジェクトの id は 4ba792d257e5fb15cc000001 のような形式の値。
  • したがって、show アクションの URL は http://localhost:3000/people/4ba792d257e5fb15cc000005 のようになる。

これは面白い。

MongoDB の説明によれば、トランザクションがない代わりに、負荷分散がやりやすい。つまり、お金やポイントの取り扱いには向かないけど、いわゆる「コンテンツ」を大量に保存するなら RDBMS より向いているかもしれない。例えば、大規模なコミュニティサイトを構築したいなら、ポイント関連のデータを MySQL に保存して、ユーザー間のメッセージなどを MongoDB に保存するといった使い分けをすればいいわけだ。