MongoDB聚合管道

本文将介绍MongoDB 聚合管道

聚合管道是建立在数据处理管道概念基础上的数据聚合框架。文档进入多级管道,将文档转换为聚合结果。例如:

db.orders.aggregate([
   { $match: { status: "A" } },
   { $group: { _id: "$cust_id", total: { $sum: "$amount" } } }
])

第一阶段:$match 按 status 字段过滤文档,并将 status 等于 “A” 的文档传递到下一阶段。

第二阶段:$group 阶段将文档按 cust_id 字段分组,以计算每个唯一 cust_id 的数量之和。

管道(Pipeline)

MongoDB 聚合管道由各个阶段组成。文档在通过管道时,每个阶段都对它们进行转换。管道的阶段不需要为每个输入文件生成一个输出文档;例如,某些阶段可能生成新文档或过滤掉文档。

管道的阶段可以在管道中多次出现,但 $out、$Merge 和 $GeoNear 阶段除外。MongoDB 在 mongo shell 中提供 db.collection.aggregate() 方法,运行聚合管道的聚合命令。

从MongoDB 4.2开始,您可以使用聚合管道进行更新:

Command

mongo Shell Methods

findAndModify

db.collection.findOneAndUpdate()

db.collection.findAndModify()

update

db.collection.updateOne()

db.collection.updateMany()

db.collection.update()

Bulk.find.update()

Bulk.find.updateOne()

Bulk.find.upsert()

例如:下面是 findOneAndUpdate、findAndModify、updateOne、updateManry 和 update 方法中使用管道。如下:

db.students2.findOneAndUpdate(
   { _id : 1 },
   [ { $set: { "total" : { $sum: "$grades.grade" } } } ],
   { returnNewDocument: true }
)

db.students2.findAndModify( {
   query: {  "_id" : 1 },
   update: [ { $set: { "total" : { $sum: "$grades.grade" } } } ],
   new: true
})

db.members.updateOne(
   { _id: 1 },
   [
      { $set: { status: "Modified", comments: [ "$misc1", "$misc2" ], lastUpdate: "$$NOW" } },
      { $unset: [ "misc1", "misc2" ] }
   ]
)

db.members.updateMany(
   { },
   [
      { $set: { status: "Modified", comments: [ "$misc1", "$misc2" ], lastUpdate: "$$NOW" } },
      { $unset: [ "misc1", "misc2" ] }
   ]
)

db.members.update(
   { },
   [
      { $set: { status: "Modified", comments: [ "$misc1", "$misc2" ], lastUpdate: "$$NOW" } },
      { $unset: [ "misc1", "misc2" ] }
   ],
   { multi: true }
)

管道表达式

有些管道阶段以管道表达式作为操作数。指定的管道表达式应用于输入文档的转换。表达式具有文档结构,可以包含其他表达式。管道表达式只能在管道中的当前文档上操作,不能引用来自其他文档中的数据:管道表达式提供了文档在内存中进行转换的操作。

通常,表达式是无状态的,只有在聚合过程看到一个例外情况时才进行计算:累加器表达式。在 $group 阶段中使用的累加器在文档通过管道时保持其状态(例如:总计、最大值、最小值和相关数据)。

3.2版本中更改

一些累加器可以在 $project 阶段使用;但是,当在 $project 阶段使用时,累加器不会跨文档维护它们的状态。

聚集管道动作

在 MongoDB 中,聚合命令对单个集合进行操作,逻辑上将整个集合传递到聚合管道中。若要优化操作,请尽可能使用以下策略以避免扫描整个集合。

管道操作和索引

MongoDB 的查询计划器分析聚合管道,以确定是否可以使用索引来提高管道性能。例如,以下管道阶段可以利用索引:

注意:以下列举的管道阶段并不代表可以使用索引的所有阶段列表。

$match

$match 阶段如果发生在管道的开头,则可以使用索引过滤文档。

$sort

$sort 阶段可以使用一个索引,只要它之前没有 $project、$unwind 或 $group 阶段。

$group

如果满足以下所有条件,$group 阶段有时可以使用索引在每个组中查找第一个文档:

  • $group 阶段之前有 $sort 阶段,该阶段对字段进行分组排序。

  • 分组字段上有一个索引,该索引与排序顺序相关。

  • $group 阶段使用的唯一累加器是 $first。

$geoNear

$geoNear 管道操作符利用地理空间索引。在使用 $geoNear 时,$geoNear 管道操作必须作为聚合管道中的第一阶段出现。

3.2版本中的变化

从MongoDB 3.2开始,索引可以覆盖聚合管道。在MongoDB 2.6和3.0中,索引不能覆盖聚合管道,因为即使管道使用索引,聚合仍然需要访问实际的文档。

早期的过滤(Early Filtering)

如果聚合操作只需要集合中数据的一个子集,那么可以使用 $match、$limit 和 $skip 阶段来限制在管道开始时输入的文档。当放置在管道的开头时,$match 操作使用合适的索引只扫描集合中匹配的文档。

在管道的开始处放置一个 $match 管道阶段,然后放置一个 $sort 阶段,这在逻辑上等同于一个带有 sort 的查询,并且可以使用索引。如果可能,在管道的开头放置 $match 操作符。

有勇气承担命运这才是英雄好汉。——黑塞
0 不喜欢
说说我的看法 -
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号