Aggregation Pipeline
Mongoid は、処理して結果を返す操作のフローを構築するために使用される MongoDB の 集計パイプラインを公開します。 集計パイプラインは、非推奨の map/reduce フレームワーク機能のスーパーセットです。
基本的な用途
複数のコレクションにわたるクエリ
集計パイプラインは、同時に参照される複数の関連付けを含むクエリに使用できます。
class Band include Mongoid::Document has_many :tours has_many :awards field :name, type: String end class Tour include Mongoid::Document belongs_to :band field :year, type: Integer end class Award include Mongoid::Document belongs_to :band field :name, type: String end
2000以降でツアー、少なくとも 1 つの賞を受賞しているバンドを検索するには、次の操作を実行します。
band_ids = Band.collection.aggregate([ { '$lookup' => { from: 'tours', localField: '_id', foreignField: 'band_id', as: 'tours', } }, { '$lookup' => { from: 'awards', localField: '_id', foreignField: 'band_id', as: 'awards', } }, { '$match' => { 'tours.year' => {'$gte' => 2000}, 'awards._id' => {'$exists' => true}, } }, {'$project' => {_id: 1}}, ]) bands = Band.find(band_ids.to_a)
集計パイプラインは、Mongoid ではなく MongoDB の Ruby ドライバーによって実装されているため、 Mongoid::Document
モデル インスタンスではなく、未加工の BSON::Document
オブジェクトを返します。 上記の例では、 _id
フィールドのみがプロジェクションされており、このフィールドは完全なモデルを読み込むために使用されます。 代替策として、そのようなプロジェクションを実行せず、未加工のフィールドを操作することにより、2 番目のクエリ(
ビルダ DSL
Mongoid は、高レベルの DSL を使用して集計パイプライン自体を構築するための限定的なサポートを提供します。 次の集計パイプライン演算子がサポートされています。
パイプラインを構築するには、 Criteria
インスタンスで対応する集計パイプライン メソッドを呼び出します。 集計パイプライン操作は、 Criteria
インスタンスのpipeline
属性に追加されます。 パイプラインを実行するには、 pipeline
属性値をCollection#aggragegate
メソッドに渡します。
次のモデルを例にしましょう。
class Tour include Mongoid::Document embeds_many :participants field :name, type: String field :states, type: Array end class Participant include Mongoid::Document embedded_in :tour field :name, type: String end
参加者が訪問した州を見つけることができます。
criteria = Tour.where('participants.name' => 'Serenity',). unwind(:states). group(_id: 'states', :states.add_to_set => '$states'). project(_id: 0, states: 1) pp criteria.pipeline # => [{"$match"=>{"participants.name"=>"Serenity"}}, # {"$unwind"=>"$states"}, # {"$group"=>{"_id"=>"states", "states"=>{"$addToSet"=>"$states"}}}, # {"$project"=>{"_id"=>0, "states"=>1}}] Tour.collection.aggregate(criteria.pipeline).to_a
グループ
group
メソッドは$group 集計パイプライン ステージを追加します。
フィールド式は Mongoid シンボル演算子構文をサポートします。
criteria = Tour.all.group(_id: 'states', :states.add_to_set => '$states') criteria.pipeline # => [{"$group"=>{"_id"=>"states", "states"=>{"$addToSet"=>"$states"}}}]
あるいは、標準の MongoDB 集計パイプライン構文を使用することもできます。
criteria = Tour.all.group(_id: 'states', states: {'$addToSet' => '$states'})
プロジェクト
project
メソッドは$project 集計パイプライン ステージを追加します。
引数は、プロジェクションを指定する ハッシュ である必要があります。
criteria = Tour.all.project(_id: 0, states: 1) criteria.pipeline # => [{"$project"=>{"_id"=>0, "states"=>1}}]
unwind
unwind
メソッドは$unwind 集計パイプライン ステージを追加します。
引数は、シンボルまたは string として指定可能なフィールド名、またはハッシュまたはBSON::Document
インスタンスにすることができます。
criteria = Tour.all.unwind(:states) criteria = Tour.all.unwind('states') criteria.pipeline # => [{"$unwind"=>"$states"}] criteria = Tour.all.unwind(path: '$states') criteria.pipeline # => [{"$unwind"=>{:path=>"$states"}}]