通过聚合转换数据
Overview
在本指南中,您可以学习;了解如何使用 Mongoid 执行聚合操作。
聚合操作处理 MongoDB 集合中的数据并返回计算结果。 MongoDB 聚合框架是 Query API 的一部分,以数据处理管道的概念为模型。 文档进入包含一个或多个阶段的管道,该管道将文档转换为聚合结果。
聚合操作的功能类似于带有装配线的汽车工厂。 装配线设有配备专用工具的工位来执行特定任务。 例如,在制造汽车时,装配线从制造车架开始。 然后,当车架移动通过装配线时,每个工位都会组装一个单独的零件。 最终产品即成品汽车。
装配线代表聚合管道,各个工位代表聚合阶段,专用工具代表表达式操作符,而成品则代表聚合结果。
比较聚合与查找操作
下表列出了使用查找操作可以执行的不同任务,同时列出了使用聚合操作可以实现的任务作为对比。聚合框架提供了扩展功能,允许您转换和操作数据。
查找操作 | 聚合操作 |
---|---|
Select certain documents to return Select which fields to return Sort the results Limit the results Count the results | Select certain documents to return Select which fields to return Sort the results Limit the results Count the results Rename fields Compute new fields Summarize data Connect and merge data sets |
Mongoid 构建器
您可以使用 Mongoid 的高级领域特定语言(DSL) 来构建聚合管道。 DSL 支持以下聚合管道操作符:
要使用上述操作符之一创建聚合管道,请在 Criteria
的实例上调用相应的方法。调用该方法会将聚合操作添加到 Criteria
实例的 pipeline
属性中。要运行聚合管道,请将 pipeline
属性值传递给 Collection#aggregate
方法。
例子
考虑一个数据库,其中包含一个文档集合,这些文档由以下类建模:
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
在此示例中,Tour
模型表示游览的名称及其途经的州,Participant
模型表示参加游览的人员的姓名。
以下示例创建了一个聚合管道,该管道使用以下聚合操作输出参与者访问过的状态:
match
,用于查找participants.name
字段值为"Serenity"
的文档unwind
,解构states
大量字段并输出大量中每个元素的文档group
,它会按文档的states
字段的值对文档进行分组project
,这会提示管道仅返回_id
和states
字段
criteria = Tour.where('participant.name' => 'Serenity'). unwind(:states). group(_id: 'states', :states.add_to_set => '$states'). project(_id: 0, states: 1) @states = Tour.collection.aggregate(criteria.pipeline).to_json
[{"states":["OR","WA","CA"]}]
不使用构建器的聚合
您可以使用 Collection#aggregate
方法通过传入聚合操作大量来运行没有相应构建器方法的聚合操作。使用此方法执行聚合会返回原始 BSON::Document
对象,而不是 Mongoid::Document
模型实例。
例子
考虑一个数据库,其中包含一个文档集合,这些文档由以下类建模:
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)
[ {"_id": "...", "name": "Deftones" }, {"_id": "...", "name": "Tool"}, ... ]
提示
前面的示例仅投影输出文档的 _id
字段。然后,它使用投影的结果查找文档并将它们作为 Mongoid::Document
模型实例返回。运行聚合管道不需要此可选步骤。
更多信息
要了解如何组装聚合管道并查看示例,请参阅聚合管道。
要了解有关创建管道阶段的更多信息,请参阅聚合阶段。
API 文档
要进一步了解本指南所讨论的任何方法,请参阅以下 API 文档: