はじめに
業務をしていく中で、mongoidを使う機会があったので、この際にmongoidの基礎をまとめてみました!
Mongoidは、RailsのActive Recordに似せて作られているみたいで、Active Recordと比較して話していきます。
Mongoidとは?
MongoDB で公式にサポートされているオブジェクト ドキュメント マッパー(ODM)
ODMとは
保存するデータを JSON ライクな形式で表現し、ドキュメントとして保存しています。このドキュメントとプログラミング言語のオブジェクトとを対応付ける機能のこと
ドキュメント
ドキュメントは Mongoid のコア オブジェクトであり、データベースに永続化するすべてのオブジェクトにはMongoid::Documentを含める必要があります。 MongoDB のドキュメントの表現は、Ruby ハッシュまたは JSON オブジェクトに非常によく似た BSON オブジェクトです。 ドキュメントは データベース内の独自のコレクションに保存することも、 n レベルの深度を持つ他のドキュメントに埋め込むこともできます。
フィールド定義
Active Recordでは、データを永続化する際、一般的にモデルとテーブルスキーマを別々に定義すると思いますが Mongoid では、モデル(フィールド)の定義のみを行います。
公式の引用
フィールドタイプの定義は、クエリを構築し、データベースからフィールドを検索/書き込みするときの Mongoid の動作を決定します
実際の書き方
Mongoidを使うには、includeでmongoidを読み込みます。
class User
include Mongoid::Document
field :name, type: String
field :email, type: String
validates :name, presence: true
end
id は、(データ型がBSON::ObjectID形式でよければ)勝手についてくるので書かなくても大丈夫です。
ここで一緒にvalidationを行うこともできます。Active Recordと似ていますね
便利メソッド
find_by
条件に従って最初のDocumentを見つけます。 一致するドキュメントが見つからず、Mongoid. Ops Manager が true に設定されている場合には、Mongoid::Errors::DocumentNotFound が発生します。それ以外の場合は、null を返します。
Person.find_by(:username => "superuser")
push
配列に単一の値または複数の値をプッシュします。
配列に単一の値をプッシュします。
document.push(names: "James", aliases: "007")
配列に複数の値をプッシュします。
document.push(names: [ "James", "Bond" ])
update
やdestory
などのActive Recordにある機能もあります
リレーションの定義の仕方
Active Recordでいうところのbelongs_to
やhas_many
といった機能が、もちろんmongoidにもあります
1 : 1
Mongoid はhas_one、 ActiveRecord ユーザーに馴染みのあるhas_many、 、belongs_toの has_and_belongs_to_many関連付けをサポートしています。
class Band
include Mongoid::Document
has_one :studio
end
class Studio
include Mongoid::Document
belongs_to :band
end
子のドキュメントに親の参照が含まれる
band = Band.create!(studio: Studio.new)
# => #<Band _id: 600114fa48966848ad5bd392, >
band.studio
# => #<Studio _id: 600114fa48966848ad5bd391, band_id: BSON::ObjectId('600114fa48966848ad5bd392')>
1 : N
関連付けを使用して、has_many親に 0 個以上の子があり、それらが別のコレクションに格納されていることを宣言します。
class Band
include Mongoid::Document
has_many :members
end
class Member
include Mongoid::Document
belongs_to :band
end
同じようにそれぞれの子のドキュメントに親の参照が含まれる
band = Band.create!(members: [Member.new])
# => #<Band _id: 6001166d4896684910b8d1c5, >
band.members
# => [#<Member _id: 6001166d4896684910b8d1c6, band_id: BSON::ObjectId('6001166d4896684910b8d1c5')>]
埋め込み関連付け 1 : 1
MongoDB のドキュメント モデルのおかげで、Mongoid は埋め込み関連付けも提供しており、異なるタイプのドキュメントを同じコレクション内に階層的に保存できます。埋め込み関連付けは
embeds_one
、embeds_many
およびembedded_in
マクロを使用して定義されます
定義
・親にembeds_oneマクロを定義。
・子にembedded_inマクロを定義。
・関連付けの両側で定義が必要です。
class Band
include Mongoid::Document
embeds_one :label
end
class Label
include Mongoid::Document
field :name, type: String
embedded_in :band
end
band = Band.create!(label: Label.new(name:'Mute'))
# => #<Band _id: 6001166d4896684910b8d1c5, >
embeds_one親のデータベース コレクション内の親内にハッシュとして保存されます。
{
"_id" : ObjectId("4d3ed089fb60ab534684b7e9"),
"label" : {
"_id" : ObjectId("4d3ed089fb60ab534684b7e0"),
"name" : "Mute",
}
}
埋め込み関連付け 1 : N
子が親ドキュメントに埋め込まれている 1 対多の関係は、Mongoidembeds_manyとembedded_inマクロを使用して定義されます。
定義
・親にembeds_manyマクロを定義。
・子にembedded_inマクロを定義。
・関連付けの両側で定義が必要です。
class Band
include Mongoid::Document
embeds_many :albums
end
class Album
include Mongoid::Document
field :name, type: String
embedded_in :band
end
embeds_many
親のデータベース コレクション内の親内にハッシュの配列として保存されます。
{
"_id" : ObjectId("4d3ed089fb60ab534684b7e9"),
"albums" : [
{
"_id" : ObjectId("4d3ed089fb60ab534684b7e0"),
"name" : "Violator",
}
]
}
まとめ
今回、Active RecordからMongoidを使ってみた感想としては、フィールド定義めっちゃ便利で楽だなと思いました。ですが、トランザクションの利用に制限があったり、外部キー制約等(合成外部キーというのがあるらしいが、、)がないこともあり、
整合性が求められるアプリケーションでは、使うことがないかもしれません😨
やっぱActive Recordですね〜
参考文献