babie steps

作業療法記録

MongoDBが起動しなくなったときの対処法(公式Ubuntuパッケージの場合)

なんかさくらのVPSが勝手にリスタートしたみたいで、MongoDBが起動しなくなった。

モッピー知ってるよ、--repair コマンド使えばいいんだよね。

$ sudo mongod --dbpath=/var/lib/mongodb --repair

あれれー?mongodb.lock ファイル消えないし、起動できないし。

ググると、公式 Ubuntu パッケージの場合はちょっと対処法がちがうっぽい:

$ sudo rm /var/lib/mongodb/mongod.lock
$ sudo -u mongodb mongod -f /etc/mongodb.conf --repair
$ sudo /etc/init.d/mongodb start

これでいけた。ふぅ・・・

Rails3 対応 MongoDB ORM、Mongoid 詳解―アップグレード

Mongoid のバージョンをアップグレードする時のリファレンスとしてご利用下さい。

2.0.0.BETA.16 + へのアップグレード

このバージョンは、MongoDB 1.6.0 を必要とします。

2.0.0.BETA.15 + へのアップグレード

もし JSON のシリアライズに include_root_in_json クラス変数を使っている場合は、もはや使用できません。現在は、mongoid.yml において、同名のグローバルな設定オプションを使用します。必要ならば、オンにしてください。(デフォルトは false です)

defaults: &defaults
  include_root_in_json: true

2.0.0.BETA.14 + へのアップグレード

フィールドの :accessible => false オプションは、attr_accessible と attr_protected を推奨するため、削除されました。モデルで定義を変更する必要があります。

gemcutter のソート順は変なので注意してください。Mongoid をアップグレードするときは、厳密にバージョンを指定しなければなりません。Bundler を使うときも、この点に気をつけてください。この Gem はすぐ配布停止されます。

2.0.0.BETA.11 + へのアップグレード

Mongoid.use_object_ids 設定オプションは削除されました。mongoid.yml または設定ブロックから削除する必要があります。

もし id を BSON::ObjectID の文字列表現として使っている場合は、以下のどちらかを行う必要があります。

a) それぞれのモデルに id を String を使うように指示します:

class Person
  include Mongoid::Document
  identity :type => String
end

b) データベースの文字列 id を ObjectID に移行します。スクリプト例は、この Gist を見てください。(Kyle Banker さんありがとう)

2.0.0.BETA.10 + へのアップグレード

smart spawning を使用している Passenger ユーザーは、フォークした時に再接続するイニシャライザを削除してください。現在は Mongoid が自動的に制御します。

preload_app を true にセットしている Unicorn ユーザーも、フォークした時に再接続するイニシャライザを削除してください。同じように、現在は Mongoid が自動的に制御します。

Rails3 対応 MongoDB ORM、Mongoid 詳解―エクステンション

FABRICATION

Paul Eliott さんの Fabrication Gem は、オブジェクト生成ライブラリです。Mongoid を最初からサポートしており、テストの簡便のために、オブジェクトを生成する素敵な構文を提供しています。

Fabricator(:person) do
  title "Grand Poobah"
  addresses(:count => 2) do |address, i|
    Fabricate(:address, :streeet => "#{i} Bond St.")
  end
end

MONGOID-RSPEC

Evan Sagge さんの mongoid-rspec は、Mongoid 用の RSpec のマッチャーを提供します。マッチャーには、関連、オプション、バリデーション、フィールドが含まれます。

describe Person do
  it { should reference_one :account }
  it { should reference_many :posts }
  it { should be_referenced_in :organization }

  it { should validate_presence_of(:name) }

  it { should have_field(:age).of_type(Integer) }
end

describe Address do
  it { should be_embedded_in(:person).as_inverse_of(:addresses) }
end

REMARKABLE

Brian Cardarella さんの remarkable-mongoid Gem は、Mongoid 用の RSpec マッチャーの素敵な代替を提供します。マッチャーは以下の例の他に、Remarkable::ActiveModel を元に、全てのバリデーションを含みます。

describe Person do

  it { should reference_one :account }
  it { should reference_many :posts }
  it { should be_referenced_in :organization }
  it { should embed_one :name }
  it { should embed_many :addresses }
  it { should be_embedded_in :group }

  it { should validate_uniqueness_of :dob }
end

RIOT

Riot-Mongoid Gem は、Mongoid 用の riot アサーションを提供します。フィールド、キー、関連、バリデーションのアサーションが含まれます。

context "Person Model" do
  setup { Person.new }

  asserts_topic.has_field :title,       :type => String

  asserts_topic.has_association :references_one, :account
  asserts_topic.has_association :embeds_many, :addresses

  asserts_topic.has_validation :validates_presence_of, :title
end


エクステンションは以上です。

Rails3 対応 MongoDB ORM、Mongoid 詳解―インテグレーション

CARRIERWAVE

ファイルアップロードを扱う Carrierwave は Mongoid をサポートしています。現在のところ、ファイルと S3 に格納することを指定できます。:mount_on オプションがアップローダークラスに定義されてない場合は、ファイル名が アップローダー名_filename をフィールド名として、格納されます。

class User
  include Mongoid::Document
  mount_uploader :avatar, AvatarUploader #field is avatar_filename
end

CUCUMBER

MongoDB はトランザクションをサポートしていないので、それぞれのフィーチャーが実行される前に、データベースがクリーンになるように、Cucumber にフックを追加したいと思います。

features/support/hooks.rb:

Mongoid.master.collections.select do |collection|
  collection.name !~ /system/
end.each(&:drop)


もし、database_cleaner という Gem を使っているなら、代わりに、features/support/database_cleaner.rb を作成してください。

require 'database_cleaner'
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.orm = "mongoid"
Before { DatabaseCleaner.clean }

RSPEC

Cucumber と同じように、RSpec の use_transactional_fixtures は Mongoid では影響しません。スイートを実行した後、データベースをクリーンにすることができます。

spec/spec_helper.rb:

Rspec.configure do |config|
  config.after :suite do
    Mongoid.master.collections.select do |collection|
      collection.name !~ /system/
    end.each(&:drop)
  end
end

おまけに :each の後何かすることもできますが、たくさんのインテグレーションスペックがある場合、遅くなるので注意してください。


もし、database_cleaner という Gem を使っているなら、代わりに、spec/spec_helper.rb の RSpec コンフィグブロックで以下の行を付け足してください。

Rspec.configure do |config|
  require 'database_cleaner'
  config.before(:suite) do
    DatabaseCleaner.strategy = :truncation
    DatabaseCleaner.orm = "mongoid"
  end

  config.before(:each) do
    DatabaseCleaner.clean
  end
end

DEVISE

Mongoid で動くように Devise をセットアップするためにやることは、ActiveRecord を呼び出しているところを削除して、Mongoid に置き換えることです。

config/initializers/devise.rb:

# ==> ORM configuration
# Load and configure the ORM. Supports :active_record (default),
# :mongoid (bson_ext recommended) and :data_mapper (experimental).
require "devise/orm/mongoid"

PASSENGER

MongoDB ウィキでは、Passenger の Smart spawning が有効なとき(デフォルトでは Conservative spawning です)、イニシャライザでインクルードする必要があると警告してますが、Mongoid では、特に何かする必要はありません。Passenger がこのモードで起動しているとき、ワーカーがフォークされたら、Mongoid はそれを検知し、再接続するようになっています。

UNICORN

Unicorn では、preload_app を true にセットする以外は、特に Mongoid で必要な設定はありません。Unicorn が子ワーカーをフォークしたら、Mongoid はそれを検知し、次のクエリでデータベースへ再接続します。


インテグレーションは以上です。

Rails3 対応 MongoDB ORM、Mongoid 詳解―Rakeタスク

Mongoid は Rails 3 環境で以下の Rake タスクを提供します。

db:create 依存関係のために存在します。実際には何もしません。
db:create_indexes モデルから全てのインデックス定義を読み取り、データベースにそれらを作成します。
db:drop システム用コレクションを除いて、全てのコレクションをデータベースから削除します。
db:migrate 依存関係のために存在します。実際には何もしません。
db:schema:load 依存関係のために存在します。実際には何もしません。
db:seed db/seeds.rb からデータベースに初期データを作成します。
db:setup インデックスを作成し、データベースに初期データを作成します。
db:test:prepare 依存関係のために存在します。実際には何もしません。


Rake タスクは以上です。

Rails3 対応 MongoDB ORM、Mongoid 詳解―その他

Mongoid にはアプリケーションで使える、いくつかの役に立つ機能があります。

マスター/スレイブ サポート

mongoid.yml でスレイブデータベースを設定しているなら、スレイブを有効化した読み取りクエリを、ラウンドロビンでスレイブデータベースを参照します。また、クエリ単位でも制御することができます。


モデルの全ての読み取りを、スレイブ間でラウンドロビンします:

class Person
  include Mongoid::Document
  enslave
end


enslave Criteria を使って、クエリ単位で、スレイブから読み取ります:

Person.where(:first_name => "Durran").enslave

キャッシュ

Mongoid は、何も設定していないそのままの状態で、大きなクエリとデータセットでメモリが効率的に使われるように、MongoDB の Ruby ドライバーのカーソルをラップしています。しかしながら、メモリの中に全てのヒットしたドキュメントをロードしたい場合や、それらをデータベースに複数回問い合わせることなく返したい場合に、cashe マクロと Criteria を使うことができます。


モデルに対する全てのクエリがキャッシュされます:

class Person
  include Mongoid::Document
  cache
end


クエリ単位でのキャッシュ:

Person.where(:first_name => "Durran").cache

ダーティー・アトリビュート

Mongoid には、ActiveModel スタイルのダーティー・アトリビュート・モジュールが実装されています。これらは、ActiveModel の API に厳密に従います:

class Person
  include Mongoid::Document
  field :first_name
end

person = Person.new(:first_name => "Leroy")
person.first_name = "Lauren"
person.changed? # true
person.first_name_changed? # true
person.first_name_was # Leroy
person.first_name_change # [ "Leroy", "Lauren" ]
person.changes # { "first_name" => [ "Leroy", "Lauren" ] }

パラノイド ドキュメント

ドキュメントを削除するとき、削除フラグをつけて、実際にはデータベースから削除したくない場合があると思います。Mongoid はそういう時のために Pranoia モジュールを提供しています。

class Person
  include Mongoid::Document
  include Mongoid::Paranoia
end

person.delete   # deleted_at フィールドに現在時刻をセットします
person.delete!  # ドキュメントを完全に削除します
person.destroy! # コールバックとともにドキュメントを完全に削除します
person.restore  # 削除されたドキュメントを復帰します

バージョン管理

Mongoid は、Mongoid::Versioning モジュールをインクルードすることにより、シンプルなバージョン管理をサポートします。このモジュールをインクルードすれば、保存の時に、version フィールドを作成します。version 番号は整数で、保存のたびに更新されます。

class Person
  include Mongoid::Document
  include Mongoid::Versioning
end


max_versions を設定することができます。Mongoid は最新のバージョンが設定された最大値を超えないようにします。

class Person
  include Mongoid::Document
  include Mongoid::Versioning

  # 最大5バージョンだけ記録する
  max_versions 5

end

タイムスタンプ

Mongoid は Mongoid::Timestamps モジュールで、タイムスタンプをサポートします。created_at と updated_at フィールドが、それぞれ自動的に付与されます。

class Person
  include Mongoid::Document
  include Mongoid::Timestamps
end

キー

key マクロを使うことで、デフォルトの id の代わりに、複合キーを作成することができます。

class Person
  include Mongoid::Document
  field :first_name
  field :last_name
  key :first_name, :last_name
end

person = Person.new(:first_name => "Syd", :last_name => "Vicious")
person.id # "syd-vicious" を返します。

違うコレクションに保存する

store_in マクロを使えば簡単です。

class Person
  include Mongoid::Document
  store_in :students
end


その他は以上です。

Rails3 対応 MongoDB ORM、Mongoid 詳解―インデックス

index マクロを使うことにより、ドキュメントにインデックスを定義することができます。:unique オプションをつけると、ユニークなインデックスを構築できます。オプションは必須ではありません。

class Person
  include Mongoid::Document
  field :ssn
  index :ssn, :unique => true
end


以下のようにして、エンベッドされたドキュメントにもインデックスを定義することができます。

class Person
  include Mongoid::Document
  embeds_many :addresses
  index "addresses.street"
end


複数フィールドに対してもインデックスを定義することができます。また、ソート順も定義できます。

  include Mongoid::Document
  field :first_name
  field :last_name
  index(
    [
      [ :first_name, Mongo::ASCENDING ],
      [ :last_name, Mongo::ASCENDING ]
    ],
    :unique => true
  )
end


インデックスは、ある程度時間がかかる場合、バックグラウンドで実行することもできます:

class Person
  include Mongoid::Document
  field :ssn
  index :ssn, :unique => true, :background => true
end


位置空間インデックスを定義する場合は、必ず、フィールドを配列としてください。

class Person
  include Mongoid::Document
  field :location, :type => Array
  index [[ :location, Mongo::GEO2D ]], :min => 200, :max => 200
end


リレーショナルな関連で、外部キーに対して、インデックスを定義することができます。

class Comment
  include Mongoid::Document
  referenced_in :post, :inverse_of => :comments, :index => true
  references_many \
    :users,
    :stored_as => :array,
    :inverse_of => :comments,
    :index => true
end


データベースにインデックスを作成したい時は、Rake タスクを呼び出してください:

rake db:create_indexes


モデルクラスがロードされたときに、自動的にインデックスを作成したい場合は、mongoid.yml のコンフィギュレーションオプションで設定することができます。ただし、プロダクション環境では推奨しません

defaults: &defaults
  autocreate_indexes: true


インデックスは以上です。