MongoDB的聚合管道
文章目录
聚合管道
MongoDB聚合管道包括阶段。每个阶段在文档通过管道时都会对其进行转换。流水线阶段不需要为每个输入文档都生成一个输出文档。例如,某些阶段可能会生成新文档或过滤掉文档。
管道阶段可以在管道中出现多次,但$out,$merge和$geoNear阶段除外。
MongoDB在mongo shell中提供了db.collection.aggregate()方法,并提供了聚合命令来运行聚合管道。
从MongoDB 4.2开始,您可以使用聚合管道在以下位置进行更新:
| 命令 | mongoshell方法 |
|---|---|
| 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() |
聚合管道表达式
一些流水线阶段将流水线表达式作为操作数。管道表达式指定要应用于输入文档的转换。表达式具有文档结构,并且可以包含其他表达式。
管道表达式只能对管道中的当前文档进行操作,而不能引用其他文档中的数据:表达式操作提供了文档的内存中转换。
通常,表达式是无状态的,只有在聚合过程中看到时才评估表达式,但有一个例外:累加器表达式。
在$group阶段中使用的累加器会随着文档在管道中的前进而保持其状态(例如,总计,最大值,最小值和相关数据)。
在版本3.2中更改:$project阶段中提供了一些累加器;但是,在$project阶段使用时,累加器不会在文档之间保持其状态。
聚合管道特性
在MongoDB中,该aggregate命令在单个集合上运行,将整个集合逻辑上传递到聚合管道中。为了尽可能优化操作,请使用以下策略来避免扫描整个集合。
管道运算符和索引
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中,索引无法覆盖聚合管道,因为即使管道使用索引,聚合仍需要访问实际文档。
早期筛选
如果聚合操作仅需要集合中数据的子集,请使用$ match,$limit和$skip阶段来限制在管道开始时输入的文档。当放置在管道的开头时,$match操作将使用适当的索引来仅扫描集合中的匹配文档。
从逻辑上讲,在管道的开头放置一个$match阶段,然后 放置一个$sort阶段,在逻辑上等效于具有排序的单个查询,并且可以使用索引。如果可能,将$match运算符放在管道的开头。
聚合管道优化
聚合管道操作具有优化阶段,该阶段尝试重塑管道以提高性能。
要查看优化器如何转换特定的聚合管道,请explain在db.collection.aggregate()方法中包括该选项 。
优化可能会在版本之间进行更改。
投影优化 聚合管道可以确定是否仅需要文档中字段的子集即可获得结果。如果是这样,管道将仅使用那些必填字段,从而减少了通过管道的数据量。
管道序列优化 ($project或$unset或$addFields或$set)+ $match序列优化 对于包含投影阶段($project或$unset或 $addFields或 $set)后跟一个 $match阶段的聚合管道,MongoDB会将$match阶段中不需要过滤阶段中计算出的值的所有过滤器移动 到投影$match之前的新阶段。
如果聚合管道包含多个投影和/或 $match阶段,则MongoDB将为每个$match阶段执行此优化 ,将每个$match过滤器移到该过滤器不依赖的所有投影阶段之前。
考虑以下阶段的管道:
{ $ addFields : { maxTime : { $ max : “ $ times” }, minTime : { $ min : “ $ times” } } }}, { $ project : {_ id : 1 , name : 1 , times : 1 , maxTime : 1 , minTime : 1 , avgTime : { $ avg : [ “ $ maxTime” , “ $ minTime” ] } } }, { $ match : { 名称: “ Joe Schmoe” , maxTime : { $ lt : 20 }, minTime : { $ gt : 5 }, avgTime : { $ gt : 7 } } } 优化器将$match阶段分为四个单独的过滤器,一个用于$match查询文档中的每个关键字。然后,优化器将每个滤波器移到尽可能多的投影阶段之前,$match根据需要创建新阶段。给定此示例,优化器将产生以下优化 管道:
{ $ match : { name : “ Joe Schmoe” } }, { $ addFields : { maxTime : { $ max : “ $ times” }, minTime : { $ min : “ $ times” } } }, { $ match : { maxTime : { $ lt : 20 }, minTime : { $ gt : 5 } } }, { $ project : {_ id : 1 , name : 1 , times : 1 , maxTime : 1 , minTime : 1 , avgTime : { $ avg : [ “ $ maxTime” , “ $ minTime” ] } } } } } { $ match : { avgTime : { $ gt : 7 } } } 该$match过滤器依赖于 舞台计算领域。该 阶段是此管道中的最后一个投影阶段,因此无法移动打开的滤镜。{ avgTime: { $gt: 7 } }$projectavgTime$project$matchavgTime
该maxTime和minTime字段计算的 $addFields阶段,但对不依赖 $project阶段。优化$match器为这些字段上的过滤器创建了一个新 阶段,并将其放置在该$project阶段之前。
该$match过滤器不使用在任一所计算的任何值或 所以它被转移到一个新的阶段 都在投影阶段之前的阶段。{ name: “Joe Schmoe” }$project$addFields$match
注意
优化后,过滤器是一个在流水线的开始阶段。这具有额外的好处,即允许聚合在最初查询集合时在字段上使用索引 。有关更多信息,请参见管道运算符和索引。{ name: “Joe Schmoe” }$matchname
$sort+ $match序列优化 当您有一个序列$sort后跟一个时 $match,请在$match之前移动, $sort以最大程度地减少要排序的对象的数量。例如,如果管道包括以下阶段:
{ $排序: { 年龄 : - 1 } }, { $比赛: { 状态: ‘A’ } } 在优化阶段,优化器将序列转换为以下内容:
{ $比赛: { 状态: ‘A’ } }, { $排序: { 年龄 : - 1 } } $redact+ $match序列优化 如果可能,当管道在$redact阶段之后紧跟着$match阶段时,聚合有时可以在$match阶段之前添加阶段 的一部分$redact。如果添加的$match阶段是在管道的开始,则聚合可以使用索引以及查询集合以限制进入管道的文档数。有关更多信息,请参见管道运算符和索引。
例如,如果管道包括以下阶段:
{ $ redact : { $ cond : { 如果: { $ eq : [ “ $ level” , 5 ] }, 然后: “ $$ PRUNE” , 否则: “ $$ DESCEND” } } }, { $ match : { 年: 2014 , 类别: { $ ne : “ Z” } } } 优化器可以在$match阶段之前添加相同的 $redact阶段:
{ $ match : { 年份: 2014 } }, { $ redact : { $ cond : { 如果: { $ eq : [ “ $ level” , 5 ] }, 然后: “ $$ PRUNE” , 否则: “ $$ DESCEND “ } } }, { $ match : { 年份: 2014 , 类别: { $ ne : ” Z“ } } } $project/ $unset+ $skip序列优化 3.2版中的新功能。
当您有一个序列,其后 跟$project或时,将 前移。例如,如果管道包括以下阶段:$unset$skip$skip$project
{ $排序: { 年龄 : - 1 } }, { $项目: { 状态: 1 , 名称: 1 } }, { $跳过: 5 } 在优化阶段,优化器将序列转换为以下内容:
{ $排序: { 年龄 : - 1 } }, { $跳过: 5 }, { $项目: { 状态: 1 , 名称: 1 } } 管道聚结优化 如果可能,优化阶段将流水线阶段合并到其前身。通常,合并发生在任何序列重新排序优化之后。
$sort+ $limit合并 在版本4.0中更改。
当一个$sort先于$limit,优化器可以聚结$limit到$sort,如果没有中间阶段的修改文件(例如,使用数$unwind,$group)。如果有管道阶段会更改和阶段之间的文档数,则MongoDB将不会合并$limit到 。$sort$sort$limit
例如,如果管道包括以下阶段:
{ $排序 : { 年龄 : - 1 } }, { $项目 : { 年龄 : 1 , 状态 : 1 , 名称 : 1 } }, { $限额: 5 } 在优化阶段,优化器将序列合并为以下内容:
{ “ $ sort” : { “ sortKey” : { “ age” : - 1 }, “ limit” : NumberLong (5 ) } }, { “ $ project” : { “ age” : 1 , “ status” : 1 , “名称” : 1 } } 这样,排序操作就可以仅在执行过程中保持最高n结果,这n是指定的限制,而MongoDB仅需要将n项目存储在内存中 [1]。有关更多信息,请参见$ sort运算符和内存。
用$ SKIP进行序列优化
如果$skip在$sort 和$limit阶段之间有一个阶段,MongoDB将合并 $limit到该$sort阶段并增加该 $limit值$skip。有关示例,请参见 $ sort + $ skip + $ limit序列。
[1] 当优化仍将适用 allowDiskUse是true与n项目超过 聚集内存限制。 $limit+ $limit合并 当$limit紧接在另一个之后 $limit,两个阶段可以合并为一个阶段 $limit,其中限制量为两个初始限制量中的较小者。例如,管道包含以下序列:
{ $ limit : 100 }, { $ limit : 10 } 然后第二$limit阶段可以合并到第一 $limit阶段并产生一个单一$limit 阶段,其中极限量10是两个初始极限100和的最小值10。
{ $ limit : 10 } $skip+ $skip合并 当$skip紧跟另一个$skip,这两个阶段可合并成一个单一的$skip,其中跳过量为总和的两个初始跳过量。例如,管道包含以下序列:
{ $ skip : 5 }, { $ skip : 2 } 然后,第二$skip阶段可以合并到第一 $skip阶段,并导致单个$skip 阶段,其中跳过量7是两个初始限制5和的总和2。
{ $ skip : 7 } $match+ $match合并 当一个$match紧随另一个紧随其后时 $match,这两个阶段可以合并为一个$match条件和一个条件 的单个步骤 $and。例如,管道包含以下序列:
{ $ match : { 年份: 2014 } }, { $ match : { 状态: “ A” } } 然后,第二$match阶段可以合并到第一 $match阶段,从而形成一个$match 阶段
{ $ match : { $ and : [ { “ year” : 2014 }, { “ status” : “ A” } ] } } $lookup+ $unwind合并 3.2版中的新功能。
当a $unwind立即紧随其后 $lookup,并且在 领域$unwind运行时,优化程序可以将其合并 到阶段中。这样可以避免创建较大的中间文档。as$lookup$unwind$lookup
例如,管道包含以下序列:
{ $ lookup : { from : “ otherCollection” , as : “ resultingArray” , localField : “ x” , foreignField : “ y” } }, { $ unwind : “ $ resultingArray” } 优化器可以将$unwind阶段合并为 $lookup阶段。如果使用explain 选项运行聚合,则explain输出将显示合并阶段:
{ $ lookup : { 来自: “ otherCollection” , 如: “ resultingArray” , localField : “ x” , foreignField : “ y” , 展开: { preserveNullAndEmptyArrays : false } } } 例子 $sort+ $skip+ $limit序列 管道包含一个序列,$sort其后是一个, $skip然后是一个$limit:
{ $排序: { 年龄 : - 1 } }, { $跳过: 10 }, { $限额: 5 } 优化程序执行$ sort + $ limit合并以将序列转换为以下内容:
{ “ $ sort” : { “ sortKey” : { “ age” : - 1 }, “ limit” : NumberLong (15 ) } }, { “ $ skip” : NumberLong (10 ) } MongoDB $limit通过重新排序增加数量。
聚合管道限制
使用该aggregate命令进行的聚合操作具有以下限制。
结果大小限制 在3.6版中进行了更改: MongoDB 3.6删除了该aggregate 命令以将其结果作为单个文档返回的选项。
该aggregate命令可以返回游标或将结果存储在集合中。当返回游标或将结果存储在集合中时,结果集中的每个文档都受到限制,目前为16兆字节;如果任何单个文档超出了 限制,该命令将产生错误。该限制仅适用于退回的文件;在管道处理过程中,文档可能会超出此大小。该 方法返回一个游标。BSON Document SizeBSON Document Sizedb.collection.aggregate()
内存限制 管道阶段的RAM限制为100 MiB(100 * 1024 * 1024字节)。如果阶段超出此限制,则MongoDB将产生错误。要允许处理大型数据集,可以在方法中设置 allowDiskUse选项 aggregate()。该allowDiskUse选项允许最多聚集流水线作业将数据写入到一个临时文件。以下聚合操作是allowDiskUse选项的例外:这些操作必须在内存限制限制内:
$graphLookup 阶段 $addToSet该$group阶段中使用的累加器表达式 (从4.2.3、4.0.14、3.6.17版开始) $push该$group阶段中使用的累加器表达式 (从4.2.3、4.0.14、3.6.17版开始) 如果管道中包括在 操作中遵守allowDiskUse:true的其他阶段aggregate(),则allowDiskUse:true选项对于这些其他阶段有效。
从MongoDB 4.2开始,事件探查器日志消息和诊断日志消息包括一个usedDisk 指示符,指示是否有任何聚合阶段由于内存限制而将数据写入临时文件。
邮政编码数据示例
数据模型
zipcodes集合中的每个文档都具有以下格式:
{ “_id” : “10280” ,“ 城市” : “纽约” , “状态” : “NY” ,“ 啪” : 5574 , “禄” : [ - 74.016323 , 40.710537 ] } 该_id字段将邮政编码保存为字符串。 该city字段包含城市名称。一个城市可以具有多个与之相关的邮政编码,因为该城市的不同部分可以分别具有不同的邮政编码。 该state字段包含两个字母的州缩写。 该pop领域拥有人口。 该loc字段将位置保存为经度纬度对。 aggregate()方法 以下所有示例均aggregate()在mongoShell中使用辅助程序。
该aggregate()方法使用 汇总管道将文档处理为汇总结果。一个聚集管道由阶段有每个阶段处理的文件,因为它们沿管道传递。文件依次经过各个阶段。
Shell中的aggregate()方法 mongo为aggregate数据库命令提供了包装 。有关用于数据聚合操作的更惯用的界面,请参见驱动程序的文档 。
返回人口超过1000万的州 以下汇总操作将返回总人口超过1000万的所有州:
db 。邮编。骨料( [ { $组: { _id : “$状态” , totalPop : { $总和: “$弹出” } } }, { $匹配: { totalPop : { $ GTE : 10 * 1000 * 1000 } } } ] ) 在此示例中,聚合管道 包括$group以下 $match阶段:
该$group阶段zipcode 按state字段将集合的文档分组,totalPop为每个状态计算字段,并为每个唯一状态输出文档。
新的按状态的文档有两个字段:_id字段和totalPop字段。该_id字段包含state; 的值 ;即按字段分组。该totalPop字段是包含每个州的总人口的计算字段。要计算该值,请$group使用$sum 运算符pop为每个州添加人口字段()。
在该$group阶段之后,管道中的文档类似于以下内容:
{ “ _id” : “ AK” , “ totalPop” : 550043 } 该$match阶段过滤这些分组的文档以仅输出totalPop值大于或等于1000万的那些文档。该$match阶段不会更改匹配的文档,但会输出未修改的匹配文档。
此聚合操作的等效SQL为:
SELECT 状态, SUM (pop ) AS totalPop 来自 邮政编码 GROUP BY 状态 HAVING totalPop > = (10 * 1000 * 1000 ) 也可以看看
$group,$match,$sum
各州返回城市平均人口数 以下汇总操作返回每个州的城市平均人口:
db 。邮编。聚合( [ {{ group : {_ id : { state : “ $ state” , city : “ $ city” }, pop : { $ sum : “ $ pop” } } }, { $ group : {_ id : “ $ _id .state“ , avgCityPop : { $ avg : ” $ pop“ } } }} ] )) 在这个例子中,聚集管道 由的$group阶段,接着是另一个 $group阶段:
第一$group阶段通过组的组合的文件city和state,使用$sum 表达式来计算的人口为每个组合,并且输出对于每个文档city和state组合。 [1]
在管道中的此阶段之后,文档类似于以下内容:
{ “ _id” : { “ state” : “ CO” , “ city” : “ EDGEWATER” }, “ pop” : 13154 } 第二$group阶段按_id.state字段(即文档state内部的字段_id)对管道中的文档进行分组,使用$avg表达式计算avgCityPop每个州的平均城市人口(),并输出每个州的文档。
此聚合操作产生的文档类似于以下内容:
{ “ _id” : “ MN” , “ avgCityPop” : 5335 } 也可以看看
$group,$sum,$avg
按州返回最大和最小城市 以下汇总操作将按人口返回每个州的最小和最大城市:
db 。邮编。聚合( [ { $ group : {_ id : { state : “ $ state” , city : “ $ city” }, pop : { $ sum : “ $ pop” } } }, { $ sort : { pop : 1 } } , { $组: { _id : “$ _id.state” , biggestCity : { $最后: “$ _id.city” }, greatPop : { $ last : “ $ pop” }, smallestCity : { $ first : “ $ _id.city” }, smallestPop : { $ first : “ $ pop” } } },
//以下$ project是可选的, //修改输出格式。
{ $ project : {_ id : 0 , 州: “ $ _id” , 最大城市: { 名称: “ $ biggestCity” , 流行音乐: “ $ biggestPop” }, 最小城市: { 名称: “ $ smallestCity” , 流行音乐: “ $ smallestPop” } } } ] ) 在此示例中,聚合管道 由一个$group阶段,一个$sort阶段,另一个$group阶段和一个$project阶段组成:
第一$group阶段通过组的组合中的文件city和state,计算sum所述的pop值对于每个组合,并且输出对于每个文档city和state组合。
在管道的此阶段,文档类似于以下内容:
{ “ _id” : { “ state” : “ CO” , “ city” : “ EDGEWATER” }, “ pop” : 13154 } 该$sort阶段订单管道由文件pop字段值,从最小到最大; 即通过增加顺序。此操作不会更改文档。
下一$group阶段按_id.state字段(即文档state内部的字段 _id)对现在分类的文档进行分组,并为每个状态输出文档。
该阶段还将为每个状态计算以下四个字段。使用$last表达式,$group操作员创建biggestCity和biggestPop字段,用于存储人口最多的城市和该人口。使用 $first表达式,$group操作员创建smallestCity和smallestPop字段,用于存储人口最少的城市和该人口。
在管道的此阶段,这些文档类似于以下内容:
{ “ _id” : “ WA” , “ biggestCity” : “ SEATTLE” , “ biggestPop ” : 520096 , “ smallestCity” : “ BENGE” , “ smallestPop” : 2 } 最后$project阶段重命名_id字段 state和移动biggestCity,biggestPop, smallestCity,和smallestPop成biggestCity和 smallestCity嵌入文档。
此聚合操作的输出文档类似于以下内容:
{ “ state” : “ RI” , “ biggestCity” : { “ name” : “ CRANSTON” , “ pop” : 176404 }, “ smallestCity” : { “ name” : “ CLAYVILLE” , “ pop” : 45 } } [1] 一个城市可以具有多个与之相关的邮政编码,因为该城市的不同部分可以分别具有不同的邮政编码。
用户偏好数据示例
数据模型 考虑一个假设的体育俱乐部,它的数据库包含一个users跟踪用户加入日期,运动偏好的 集合,并将这些数据存储在类似于以下内容的文档中:
{ _id : “ jane” , 加入 : ISODate (“ 2011-03-02” ), 喜欢 : [[ “高尔夫球” , “壁球” ] } { _id : “ joe” , 加入 : ISODate (“ 2012-07-02” ), 喜欢 : [[ 网球] , “高尔夫” , “游泳” ] } 对文档进行规范化和排序 以下操作以大写字母顺序返回用户名。聚合包括users集合中所有文档的用户名。您可以执行此操作以标准化用户名以进行处理。
db 。用户。骨料( [ { $项目 : { 名称:{ $ TOUPPER :“$ _id” } , _id :0 } }, { $排序 : { 名称 : 1 } } ] ) users集合中的所有文档都通过管道,该管道包括以下操作:
该$project操作: 创建一个名为的新字段name。 _id使用$toUpper运算符将的值转换为大写 。然后, $project创建一个新字段,命名name 为保留该值。 抑制该id字段。除非明确禁止,否则默认情况下$project将通过该_id字段。 该$sort运营商的订单,结果由 name现场。 聚合的结果类似于以下内容:
{ “ name” : “ JANE” }, { “ name” : “ JILL” }, { “ name” : “ JOE” } 返回按加入月份排序的用户名 以下聚合操作返回按其加入月份排序的用户名。这种聚合可以帮助生成成员资格更新通知。
db 。用户。骨料( [ { $项目 : { month_joined : { $月 : “$加入” }, 名称 : “$ _id” , _id : 0 } }, { $排序 : { month_joined : 1 } } ] ) 管道通过users以下操作传递集合中的所有文档:
该$project操作: 创建两个新字段:month_joined和name。 id从结果中抑制。除非明确禁止,否则该aggregate()方法包括_id。 该$month运营商的值转换 joined领域月份的整数表示。然后, $project操作员将这些值分配给该 month_joined字段。 该$sort操作通过排序的结果 month_joined字段。 该操作返回类似于以下内容的结果:
{ “ month_joined” : 1 , “ name” : “ ruth” }, { “ month_joined” : 1 , “ name” : “ harold” }, { “ month_joined” : 1 , “ name” : “ kate” } { “ month_joined “ : 2 , ” name“ : ” jill“ } 返回每月的加入总数 以下操作显示一年中每个月有多少人加入。您可以将这些汇总数据用于招聘和营销策略。
db 。用户。骨料( [ { $项目 : { month_joined : { $月 : “$加入” } } } , { $组 : { _id : { month_joined :“$ month_joined” } , 编号 : { $总和 : 1 } } }, { $ sort : { “ _id.month_joined” : 1 } } ] ) 管道通过users以下操作传递集合中的所有文档:
在$project操作创建一个名为新的领域 month_joined。 该$month运营商的值转换 joined领域月份的整数表示。然后, $project操作员将值分配给该 month_joined字段。 该$group运营商收集与给定的所有文件month_joined的价值和次数多少文件有该值。具体来说,对于每个唯一值, $group使用两个字段创建一个新的“每月”文档: _id,其中包含带有该month_joined字段及其值的嵌套文档 。 number,这是一个生成的字段。$sum 对于每个包含给定month_joined值的文档,操作员将该字段增加1 。 该$sort运营商排序由创建的文档 $group根据内容 month_joined领域。 此聚合操作的结果类似于以下内容:
{ “ _id” : { “ month_joined” : 1 }, “数字” : 3 }, { “ _id” : { “ month_joined” : 2 }, “数字” : 9 }, { “ _id” : { “ month_joined” : 3 }, “数字” : 5 } 返回五个最常见的“喜欢” 以下汇总收集了数据集中前五个最“喜欢”的活动。这种类型的分析可以帮助规划和未来开发。
db 。用户。骨料( [ { $展开 : “$喜欢” }, { $组 : { _id : “$喜欢” , 编号 : { $总和 : 1 } } }, { $排序 : { 数 : - 1 } }, { $限制 : 5 } ] ) 管道以users集合中的所有文档开始,并通过以下操作传递这些文档:
的$unwind操作者中的每个值分隔 likes阵列,以及用于所述阵列中的每个元素创建源文档的新版本。
例
给定users集合中的以下文档:
{ _id : “ jane” , 加入后 : ISODate (“ 2011-03-02” ), 喜欢 : [ “ golf” , “壁球” ] } 该$unwind运营商将创建下列文件:
{ _id : “ jane” , 加入 : ISODate (“ 2011-03-02” ), 喜欢 : “ golf” } { _id : “ jane” , 加入 : ISODate (“ 2011-03-02” ), 喜欢 : “壁球“ } 该$group运营商收集与为同一值的所有文档likes领域,并计算各分组。利用此信息,$group创建具有两个字段的新文档:
_id,其中包含likes值。 number,这是一个生成的字段。$sum 对于每个包含给定likes值的文档,操作员将该字段增加1 。 该$sort运营商排序这些文件由 number以相反的顺序领域。
该$limit操作仅包括前5个结果文档。
聚合的结果类似于以下内容:
{ “ _id” : “高尔夫球” , “数字” : 33 }, { “ _id” : “壁球” , “数字” : 31 }, { “ _id” : “游泳” , “数字” : 24 }, { “ _id“ : ”手球“ , ”数字“ : 19 }, { ” _id“ : ”网球“ , ”数字“ : 18 }
文章作者 Forz
上次更新 2020-05-17