聚合管道 (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以来巡回演出并至少获得一项奖项的乐队,可以执行以下操作:
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)
请注意,聚合管道是由MongoDB的Ruby驾驶员而不是 Mongoid 实施的,因此会返回原始 BSON::Document
对象,而不是Mongoid::Document
模型实例。 上述示例仅_id
字段,该字段随后用于加载完整模型。 另一种方法是不执行此类投影并使用原始字段,这样就无需在第二个查询(可能很大)中将文档ID 列表发送到 Mongoid。
Builder 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
方法添加一个$ 项目聚合管道阶段。
参数应该是指定投影的哈希:
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"}}]