前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MongoDB入门(四)

MongoDB入门(四)

原创
作者头像
传说之下的花儿
发布2023-11-26 19:32:08
2570
发布2023-11-26 19:32:08
举报

8. MongoDB 聚合

将记录按条件分组以后,然后再进行一系列操作,例如,求最大值、最小值、平均值,求和等操作。聚合操作还能够对记录进行复杂的操作,主要用于数理统计和数据挖掘。

aggregate() 方法的基本语法格式如下所示:

代码语言:javascript
复制
 > db.COLLECTION_NAME.aggregate([
                     {<stage>},
                     ...
                     ])

MongoDB 提供了非常强大的聚合操作,有三种方式:

  • 聚合管道(Aggregation Pipeline)
  • 单目的聚合操作(Single Purpose Aggregation Operation)
  • MapReduce 编程模型

在本篇中,重点讲解聚合管道和单目的聚合操作,MapReduce 编程模型会在后续的文章中讲解。

8.1 聚合管道

聚合管道是 MongoDB 2.2版本引入的新功能。它由阶段(Stage)组成,文档在一个阶段处理完毕后,聚合管道会把处理结果传到下一个阶段。

聚合管道功能:

  • 对文档进行过滤,查询出符合条件的文档
  • 对文档进行变换,改变文档的输出形式

每个阶段用阶段操作符(Stage Operators)定义,在每个阶段操作符中可以用表达式操作符(Expression Operators)计算总和、平均值、拼接分割字符串等相关操作,直到每个阶段进行完成,最终返回结果,返回的结果可以直接输出,也可以存储到集合中。

MongoDB 中使用 db.COLLECTION_NAME.aggregate([{<stage>},...]) 方法来构建和使用聚合管道。

先看下官网给的实例,感受一下聚合管道的用法。

实例中,$match 用于获取 status = "A" 的记录,然后将符合条件的记录送到下一阶段 $group中根据cust_id进行分组并对amount进行求和计算,最后返回 Results。

其中,match、group 都是阶段操作符,而阶段 group 中用到的 sum 是表达式操作符。

8.1.1 阶段操作符
8.1.1 阶段操作符

使用阶段操作符之前,我们先看一下 article 集合中的文档列表,也就是范例中用到的数据。

代码语言:javascript
复制
 >db.article.find().pretty()
 {
    "_id": ObjectId("58e1d2f0bb1bbc3245fa7570")
    "title": "MongoDB Aggregate",
    "author": "liruihuan",
    "tags": ['Mongodb', 'Database', 'Query'],
    "pages": 5,
    "time" : ISODate("2017-04-09T11:42:39.736Z")
 },
 {
    "_id": ObjectId("58e1d2f0bb1bbc3245fa7571")
    "title": "MongoDB Index",
    "author": "liruihuan",
    "tags": ['Mongodb', 'Index', 'Query'],
    "pages": 3,
    "time" : ISODate("2017-04-09T11:43:39.236Z")
 },
 {
    "_id": ObjectId("58e1d2f0bb1bbc3245fa7572")
    "title": "MongoDB Query",
    "author": "eryueyang",
    "tags": ['Mongodb', 'Query'],
    "pages": 8,
    "time" : ISODate("2017-04-09T11:44:56.276Z")
 }

$project:修改文档的结构,可以用来重命名、增加或删除文档中的字段。

示例1:

只返回文档中 title 和 author 字段

代码语言:javascript
复制
>db.article.aggregate([
                {$project:{_id:0, title:1, author:1 }}
                ])
{ "title": "MongoDB Aggregate",  "author": "liruihuan" },
{ "title": "MongoDB Index",  "author": "liruihuan" },
{ "title": "MongoDB Query",  "author": "eryueyang" }

因为字段 id 是默认显示的,这里必须用 _id:0 把字段id过滤掉。

示例2 :

把文档中 pages 字段的值都增加10。并重命名成 newPages 字段。

代码语言:javascript
复制
>db.article.aggregate(
   [
      {
          $project:{
               _id:0,
               title:1,
               author:1,
               newPages: {$add:["$Pages",10]}
         }
      },
   ]
)
{ "title": "MongoDB Aggregate",  "author": "liruihuan", "newPages": 15 },
{ "title": "MongoDB Index",  "author": "liruihuan", "newPages": 13  },
{ "title": "MongoDB Query",  "author": "eryueyang", "newPages": 18  }

其中,$add 是 加 的意思,是算术类型表达式操作符,具体表达式操作符,下面会讲到。

$match:用于过滤文档。用法类似于 find() 方法中的参数。 范例 查询出文档中 pages 字段的值大于等于5的数据。

代码语言:javascript
复制
>db.article.aggregate(
    [
         {
              $match: {"pages": {$gte: 5}}
         }
    ]
   ).pretty()
   
{
   "_id": ObjectId("58e1d2f0bb1bbc3245fa7570")
   "title": "MongoDB Aggregate",
   "author": "liruihuan",
   "tags": ['Mongodb', 'Database', 'Query'],
   "pages": 5,
   "time" : ISODate("2017-04-09T11:42:39.736Z")
},
{
   "_id": ObjectId("58e1d2f0bb1bbc3245fa7572")
   "title": "MongoDB Query",
   "author": "eryueyang",
   "tags": ['Mongodb', 'Query'],
   "pages": 8,
   "time" : ISODate("2017-04-09T11:44:56.276Z")
}

注:

  • 在 match 中不能使用 where 表达式操作符
  • 如果 $match 位于管道的第一个阶段,可以利用索引来提高查询效率
  • match 中使用 text 操作符的话,只能位于管道的第一阶段
  • $match 尽量出现在管道的最前面,过滤出需要的数据,在后续的阶段中可以提高效率。

$group:将集合中的文档分组,可用于统计结果。

范例

从 article 中得到每个 author 的文章数,并输入 author 和对应的文章数。

代码语言:javascript
复制
db.article.aggregate(
	[
		{
			$group:{_id:'$author',total:{$sum:1}}
		}
	]
)
{"_id" : "eryueyang", "total" : 1}
{"_id" : "liruihuan", "total" : 2}

$sort:将集合中的文档进行排序。

范例

让集合 article 以 pages 升序排列

代码语言:javascript
复制
>db.article.aggregate(
	[
		{
			$sort: {"pages": 1}
        }
    ]
).pretty()

{
   "_id": ObjectId("58e1d2f0bb1bbc3245fa7571")
   "title": "MongoDB Index",
   "author": "liruihuan",
   "tags": ['Mongodb', 'Index', 'Query'],
   "pages": 3,
   "time" : ISODate("2017-04-09T11:43:39.236Z")
},
{
   "_id": ObjectId("58e1d2f0bb1bbc3245fa7570")
   "title": "MongoDB Aggregate",
   "author": "liruihuan",
   "tags": ['Mongodb', 'Database', 'Query'],
   "pages": 5,
   "time" : ISODate("2017-04-09T11:42:39.736Z")
},
{
   "_id": ObjectId("58e1d2f0bb1bbc3245fa7572")
   "title": "MongoDB Query",
   "author": "eryueyang",
   "tags": ['Mongodb', 'Query'],
   "pages": 8,
   "time" : ISODate("2017-04-09T11:44:56.276Z")
}

如果以降序排列,则设置成 "pages": -1

$limit:限制返回的文档数量。

范例

返回集合 article 中前两条文档

代码语言:javascript
复制
>db.article.aggregate(
	[
		{
			$limit: 2
        }
     ]
).pretty()
{
   "_id": ObjectId("58e1d2f0bb1bbc3245fa7570")
   "title": "MongoDB Aggregate",
   "author": "liruihuan",
   "tags": ['Mongodb', 'Database', 'Query'],
   "pages": 5,
   "time" : ISODate("2017-04-09T11:42:39.736Z")
},
{
   "_id": ObjectId("58e1d2f0bb1bbc3245fa7571")
   "title": "MongoDB Index",
   "author": "liruihuan",
   "tags": ['Mongodb', 'Index', 'Query'],
   "pages": 3,
   "time" : ISODate("2017-04-09T11:43:39.236Z")
}

$skip:跳过指定数量的文档,并返回余下的文档。

范例

跳过集合 article 中一条文档,输出剩下的文档

代码语言:javascript
复制
>db.article.aggregate([
		{$skip: 1}
]).pretty()
{
   "_id": ObjectId("58e1d2f0bb1bbc3245fa7571")
   "title": "MongoDB Index",
   "author": "liruihuan",
   "tags": ['Mongodb', 'Index', 'Query'],
   "pages": 3,
   "time" : ISODate("2017-04-09T11:43:39.236Z")
},
{
   "_id": ObjectId("58e1d2f0bb1bbc3245fa7572")
   "title": "MongoDB Query",
   "author": "eryueyang",
   "tags": ['Mongodb', 'Query'],
   "pages": 8,
   "time" : ISODate("2017-04-09T11:44:56.276Z")
}

$unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。

范例

把集合 article 中 title="MongoDB Aggregate" 的 tags 字段拆分

代码语言:javascript
复制
>db.article.aggregate(
    [
         {$match: {"title": "MongoDB Aggregate"}},
         {$unwind: "$tags"},
    ]
   ).pretty()
{
   "_id": ObjectId("58e1d2f0bb1bbc3245fa7570")
   "title": "MongoDB Aggregate",
   "author": "liruihuan",
   "tags": "Mongodb",
   "pages": 5,
   "time" : ISODate("2017-04-09T11:42:39.736Z")
},
{
   "_id": ObjectId("58e1d2f0bb1bbc3245fa7570")
   "title": "MongoDB Aggregate",
   "author": "liruihuan",
   "tags": "Database",
   "pages": 5,
   "time" : ISODate("2017-04-09T11:42:39.736Z")
},
{
   "_id": ObjectId("58e1d2f0bb1bbc3245fa7570")
   "title": "MongoDB Aggregate",
   "author": "liruihuan",
   "tags": "Query",
   "pages": 5,
   "time" : ISODate("2017-04-09T11:42:39.736Z")
}

注:

  • $unwind 参数数组字段为空或不存在时,待处理的文档将会被忽略,该文档将不会有任何输出
  • $unwind 参数不是一个数组类型时,将会抛出异常
  • $unwind 所作的修改,只用于输出,不能改变原文档

8.1.2 表达式操作符

表达式操作符有很多操作类型,其中最常用的有布尔管道聚合操作、集合操作、比较聚合操作、算术聚合操作、字符串聚合操作、数组聚合操作、日期聚合操作、条件聚合操作、数据类型聚合操作等。

每种类型都有很多用法,这里就不一一举例了。

布尔管道聚合操作(Boolean Aggregation Operators)

名称

说明

$and

仅当其所有表达式的计算结果为true时,才返回true。接受任意数量的参数表达式。

$or

当其任何表达式的计算结果为true时,返回true。接受任意数量的参数表达式。

$not

返回与其参数表达式相反的布尔值。接受单个参数表达式。

范例

假如有一个集合 mycol

代码语言:javascript
复制
{ "_id" : 1, "item" : "abc1", description: "product 1", qty: 300 }
{ "_id" : 2, "item" : "abc2", description: "product 2", qty: 200 }
{ "_id" : 3, "item" : "xyz1", description: "product 3", qty: 250 }
{ "_id" : 4, "item" : "VWZ1", description: "product 4", qty: 300 }
{ "_id" : 5, "item" : "VWZ2", description: "product 5", qty: 180 }

确定 qty 是否大于250或者小于200

代码语言:javascript
复制
db.mycol.aggregation(
	[
		{
			$project : 
				{
					item : 1,
					result : 
						{
							$or:
								[
									{$gt:["$qty",250]},
									{$lt:["$qty",200]}
								]
						}
				}
		}
	]
)
{ "_id" : 1, "item" : "abc1", "result" : true }
{ "_id" : 2, "item" : "abc2", "result" : false }
{ "_id" : 3, "item" : "xyz1", "result" : false }
{ "_id" : 4, "item" : "VWZ1", "result" : true }
{ "_id" : 5, "item" : "VWZ2", "result" : true }
集合操作(Set Operators)

用于集合操作,求集合的并集、交集、差集运算。

名称

说明

$setEquals

相等集 如果输入集具有相同的不同元素,则返回'true'。接受两个或多个参数表达式。

$setIntersection

交集 返回一个集合,其中的元素出现在所有输入集中。接受任意数量的参数表达式。

$setUnion

并集 返回包含在任意输入集中出现的元素的集合。接受任意数量的参数表达式。

$setDifference

差集 Returns a set with elements that appear in the first set but not in the second set; i.e. performs a relative complement of the second set relative to the first. Accepts exactly two argument expressions.

$setIsSubset

包含 如果第一个集合的所有元素都出现在第二个集合中,包括当第一个集合等于第二个集合时,返回'true';i、 不是严格的子集。只接受两个参数表达式。

$anyElementTrue

如果集合的任意元素的值为true,则返回true;否则,返回'false'。接受单个参数表达式。

$allElementsTrue

如果集合的没有元素的计算结果为'false',则返回'true',否则返回'false'。接受单个参数表达式。

范例

假如有一个集合 mycol

代码语言:javascript
复制
{ "_id" : 1, "A" : [ "red", "blue" ], "B" : [ "red", "blue" ] }
{ "_id" : 2, "A" : [ "red", "blue" ], "B" : [ "blue", "red", "blue" ] }
{ "_id" : 3, "A" : [ "red", "blue" ], "B" : [ "red", "blue", "green" ] }
{ "_id" : 4, "A" : [ "red", "blue" ], "B" : [ "green", "red" ] }
{ "_id" : 5, "A" : [ "red", "blue" ], "B" : [ ] }
{ "_id" : 6, "A" : [ "red", "blue" ], "B" : [ [ "red" ], [ "blue" ] ] }
{ "_id" : 7, "A" : [ "red", "blue" ], "B" : [ [ "red", "blue" ] ] }
{ "_id" : 8, "A" : [ ], "B" : [ ] }
{ "_id" : 9, "A" : [ ], "B" : [ "red" ] }

求出集合 mycol 中 A 和 B 的交集

代码语言:javascript
复制
db.mycol.aggregate(
   [
     { $project: { A:1, B: 1, allValues: { $setUnion: [ "$A", "$B" ] }, _id: 0 } }
   ]
)
{ "A": [ "red", "blue" ], "B": [ "red", "blue" ], "allValues": [ "blue", "red" ] }
{ "A": [ "red", "blue" ], "B": [ "blue", "red", "blue" ], "allValues": [ "blue", "red" ] }
{ "A": [ "red", "blue" ], "B": [ "red", "blue", "green" ], "allValues": [ "blue", "red", "green" ] }
{ "A": [ "red", "blue" ], "B": [ "green", "red" ], "allValues": [ "blue", "red", "green" ] }
{ "A": [ "red", "blue" ], "B": [ ], "allValues": [ "blue", "red" ] }
{ "A": [ "red", "blue" ], "B": [ [ "red" ], [ "blue" ] ], "allValues": [ "blue", "red", [ "red" ], [ "blue" ] ] }
{ "A": [ "red", "blue" ], "B": [ [ "red", "blue" ] ], "allValues": [ "blue", "red", [ "red", "blue" ] ] }
{ "A": [ ], "B": [ ], "allValues": [ ] }
{ "A": [ ], "B": [ "red" ], "allValues": [ "red" ] }
比较聚合操作(Comparison Aggregation Operators)

名称

说明

$cmp

比较 如果两个值相等,则返回“0”;如果第一个值大于第二个值,则返回“1”;如果第一个值小于第二个值,则返回“1”。

$eq

比较 如果值相等,则返回'true'。

$gt

大于 如果第一个值大于第二个值,则返回'true'。

$gte

大于等于

$lt

小于 如果第一个值小于于第二个值,则返回'true'。

$lte

小于等于

$ne

不等于

算术聚合操作(Arithmetic Aggregation Operators)

名称

说明

$abs

返回数字的绝对值

$add

添加数字以返回总和,或添加数字和日期以返回新日期。 如果添加数字和日期,则将数字视为毫秒。 接受任意数量的参数表达式,但最多一个表达式可以解析为一个日期。

$ceil

向上取整

$divide

返回第一个数除以第二个数的结果。

$exp

a的x次方

$floor

向下取整

$ln

计算数字的自然对数。

$log

计算指定基数中某个数字的对数。

$log10

计算一个数字的对数基数10。

$mod

返回第一个数除以第二个数的余数。

$multiply

Multiplies numbers to return the product. Accepts any number of argument expressions.

$pow

将数字相乘以返回结果。接受任意数量的参数表达式。

$sqrt

计算平方根。

$subtract

返回从第一个值减去第二个值的结果。 如果这两个值是数字,则返回差值。 如果这两个值是日期,则返回以毫秒为单位的差值。 如果这两个值是日期和毫秒数,则返回结果日期。 接受两个参数表达式。 如果这两个值是日期和数字,请首先指定日期参数,因为从数字中减去日期没有意义。

$trunc

将数字截断为其整数。

范例

假如有一个集合 mycol

代码语言:javascript
复制
{ _id: 1, start: 5, ``end``: 8 }
{ _id: 2, start: 4, ``end``: 4 }
{ _id: 3, start: 9, ``end``: 7 }
{ _id: 4, start: 6, ``end``: 7 }

求集合 mycol 中 start 减去 end 的绝对值

代码语言:javascript
复制
db.mycol.aggregate(
	{
		$project: {delta:{ $abs: {$subtract:["$start","$end"]}}}
	}
)
{ "_id" : 1, "delta" : 3 }
{ "_id" : 2, "delta" : 0 }
{ "_id" : 3, "delta" : 2 }
{ "_id" : 4, "delta" : 1 }
字符串聚合操作(String Aggregation Operators)

名称

说明

$concat

连接任意数量的字符串。

$indexOfBytes

在字符串中搜索子字符串的出现,并返回第一次出现的UTF-8字节索引。如果未找到子字符串,则返回“-1”。

$indexOfCP

在字符串中搜索子字符串的出现,并返回第一次出现的UTF-8代码点索引。如果未找到子字符串,则返回“-1”。

$split

根据分隔符将字符串拆分为子字符串。返回子字符串数组。如果在字符串中找不到分隔符,则返回包含原始字符串的数组。

$strLenBytes

返回字符串中UTF-8编码的字节数。

$strLenCP

返回字符串中UTF-8代码点的数目。

$strcasecmp

执行不区分大小写的字符串比较并返回:如果两个字符串相等,则返回“0”;如果第一个字符串大于第二个字符串,则返回“1”;如果第一个字符串小于第二个字符串,则返回“1”。

$substrBytes

返回字符串的子字符串。从字符串中指定的UTF-8字节索引(从零开始)处的字符开始,并持续指定的字节数。

$substrCP

返回字符串的子字符串。从字符串中指定的UTF-8代码点(CP)索引(从零开始)处的字符开始,并按指定的代码点数继续。

$toLower

将字符串转换为小写。接受单个参数表达式。

$toUpper

将字符串转换为大写。接受单个参数表达式。

范例

假如有一个集合 mycol

代码语言:javascript
复制
{ "_id" : 1, "city" : "Berkeley, CA", "qty" : 648 }
{ "_id" : 2, "city" : "Bend, OR", "qty" : 491 }
{ "_id" : 3, "city" : "Kensington, CA", "qty" : 233 }
{ "_id" : 4, "city" : "Eugene, OR", "qty" : 842 }
{ "_id" : 5, "city" : "Reno, NV", "qty" : 655 }
{ "_id" : 6, "city" : "Portland, OR", "qty" : 408 }
{ "_id" : 7, "city" : "Sacramento, CA", "qty" : 574 }

以 ',' 分割集合 mycol 中字符串city的值,

用 $unwind 拆分成多个文档,

匹配出城市名称只有两个字母的城市,

并求和各个城市中 qty 的值,

最后以降序排序。

代码语言:javascript
复制
db.mycol.aggregate([
  { $project : { city_state : { $split: ["$city", ", "] }, qty : 1 } },
  { $unwind : "$city_state" },
  { $match : { city_state : /[A-Z]{2}/ } },
  { $group : { _id: { "state" : "$city_state" }, total_qty : { "$sum" : "$qty" } } },
  { $sort : { total_qty : -1 } }
])
{ "_id" : { "state" : "OR" }, "total_qty" : 1741 }
{ "_id" : { "state" : "CA" }, "total_qty" : 1455 }
{ "_id" : { "state" : "NV" }, "total_qty" : 655 }
数组聚合操作(Array Aggregation Operators)

名称

说明

$arrayElemAt

返回指定数组索引处的元素。

$concatArrays

连接数组以返回连接的数组。

$filter

选择数组的子集以返回仅包含与筛选条件匹配的元素的数组。

$indexOfArray

在数组中搜索指定值的出现,并返回第一次出现的数组索引。如果未找到子字符串,则返回“-1”。

$isArray

确定操作数是否为数组。返回一个布尔值。

$range

根据用户定义的输入输出包含整数序列的数组。

$reverseArray

返回元素顺序相反的数组。

$reduce

将表达式应用于数组中的每个元素,并将它们组合为单个值。

$size

返回数组中的元素数。接受单个表达式作为参数。

$slice

返回数组的子集。

$zip

将两个列表合并在一起。

$in

返回一个布尔值,指示指定值是否在数组中。

范例

假如有一个集合 mycol

代码语言:javascript
复制
{ "_id" : 1, "name" : "dave123", favorites: [ "chocolate", "cake", "butter", "apples" ] }
{ "_id" : 2, "name" : "li", favorites: [ "apples", "pudding", "pie" ] }
{ "_id" : 3, "name" : "ahn", favorites: [ "pears", "pecans", "chocolate", "cherries" ] }
{ "_id" : 4, "name" : "ty", favorites: [ "ice cream" ] }

求出集合 mycol 中 favorites 的第一项和最后一项

代码语言:javascript
复制
db.mycol.aggregate([
	{$project:{
		name :1;
		first:{$arrayElemAt:["$favorites",0]},
		last: {$arrayElemAt:["$favorites",-1]}
	}}
])
{ "_id" : 1, "name" : "dave123", "first" : "chocolate", "last" : "apples" }
{ "_id" : 2, "name" : "li", "first" : "apples", "last" : "pie" }
{ "_id" : 3, "name" : "ahn", "first" : "pears", "last" : "cherries" }
{ "_id" : 4, "name" : "ty", "first" : "ice cream", "last" : "ice cream" }
日期聚合操作(Date Aggregation Operators)

名称

说明

$dayOfYear

以介于1和366(闰年)之间的数字返回日期的日期。

$dayOfMonth

以1到31之间的数字返回日期的月份日期。

$dayOfWeek

以1(星期日)到7(星期六)之间的数字形式返回日期的星期几。

$year

以数字形式返回日期的年份(例如2014年)。

$month

将日期的月份返回为介于1(一月)和12(十二月)之间的数字。

$week

将日期的周数作为介于0(一年中第一个星期日之前的部分周)和53(闰年)之间的数字返回。

$hour

以0到23之间的数字返回日期的小时数。

$minute

以0到59之间的数字形式返回日期的分钟。

$second

以0到60之间的数字(闰秒)返回日期的秒数。

$millisecond

以介于0和999之间的数字形式返回日期的毫秒数。

$dateToString

以格式化字符串的形式返回日期。

$isoDayOfWeek

返回ISO 8601格式的工作日编号,范围从“1”(星期一)到“7”(星期日)。

$isoWeek

返回ISO 8601格式的周数,范围从'1'到'53'。周数从'1'开始,以包含一年中第一个星期四的一周(周一到周日)为单位。

$isoWeekYear

返回ISO 8601格式的年份号。一年从第一周的星期一开始(ISO 8601),到最后一周的星期日结束(ISO 8601)。

范例

假如有一个集合 mycol

代码语言:javascript
复制
{ 
	"_id" : 1,
    "item" : "abc",
    "price" : 10,
    "quantity" : 2,
    "date" : ISODate("2017-01-01T08:15:39.736Z") 
}

得到集合 mycol 中 date 字段的相关日期值

代码语言:javascript
复制
db.mycol.aggregate(
  ``[
   ``{
    ``$project:
     ``{
      ``year``: { $``year``: ``"$date"` `},
      ``month``: { $``month``: ``"$date"` `},
      ``day``: { $dayOfMonth: ``"$date"` `},
      ``hour``: { $``hour``: ``"$date"` `},
      ``minutes: { $``minute``: ``"$date"` `},
      ``seconds: { $``second``: ``"$date"` `},
      ``milliseconds: { $millisecond: ``"$date"` `},
      ``dayOfYear: { $dayOfYear: ``"$date"` `},
      ``dayOfWeek: { $dayOfWeek: ``"$date"` `},
      ``week: { $week: ``"$date"` `}
     ``}
   ``}
  ``]
)
{
 ``"_id"` `: 1,
 ``"year"` `: 2017,
 ``"month"` `: 1,
 ``"day"` `: 1,
 ``"hour"` `: 8,
 ``"minutes"` `: 15,
 ``"seconds"` `: 39,
 ``"milliseconds"` `: 736,
 ``"dayOfYear"` `: 1,
 ``"dayOfWeek"` `: 1,
 ``"week"` `: 0
}
条件聚合操作(Conditional Aggregation Operators)

名称

说明

$cond

三元运算符,对一个表达式求值,并根据结果返回其他两个表达式之一的值。接受有序列表中的三个表达式或三个命名参数。

$ifNull

返回第一个表达式的非空结果,如果第一个表达式的结果为空,则返回第二个表达式的结果。Null结果包含未定义值或缺少字段的实例。接受两个表达式作为参数。第二个表达式的结果可以为null。

$switch

计算一系列大小写表达式。当它找到一个计算结果为“true”的表达式时,“$switch”执行指定的表达式并中断控制流。

范例

假如有一个集合 mycol

代码语言:javascript
复制
{ "_id" : 1, "item" : "abc1", qty: 300 }
{ "_id" : 2, "item" : "abc2", qty: 200 }
{ "_id" : 3, "item" : "xyz1", qty: 250 }

如果集合 mycol 中 qty 字段值大于等于250,则返回30,否则返回20

代码语言:javascript
复制
db.mycol.aggregate(
   [
      {
         $project:
           {
             item: 1,
             discount:
               {
                 $cond: { if: { $gte: [ "$qty", 250 ] }, then: 30, else: 20 }
               }
           }
      }
   ]
)
{ "_id" : 1, "item" : "abc1", "discount" : 30 }
{ "_id" : 2, "item" : "abc2", "discount" : 20 }
{ "_id" : 3, "item" : "xyz1", "discount" : 30 }
数据类型聚合操作(Data Type Aggregation Operators)

名称

说明

$type

返回字段的BSON数据类型。

范例

假如有一个集合 mycol

代码语言:javascript
复制
 { _id: 0, a : 8 }
 { _id: 1, a : [ 41.63, 88.19 ] }
 { _id: 2, a : { a : "apple", b : "banana", c: "carrot" } }
 { _id: 3, a :  "caribou" }
 { _id: 4, a : NumberLong(71) }
 { _id: 5 }

获取文档中 a 字段的数据类型

代码语言:javascript
复制
db.mycol.aggregate([{
    $project: {
       a : { $type: "$a" }
    }
}])
{ _id: 0, "a" : "double" }
{ _id: 1, "a" : "array" }
{ _id: 2, "a" : "object" }
{ _id: 3, "a" : "string" }
{ _id: 4, "a" : "long" }
{ _id: 5, "a" : "missing" }
8.1.3 聚合管道优化

默认情况下,整个集合作为聚合管道的输入,为了提高处理数据的效率,可以使用一下策略:

  • 将 match 和 sort 放到管道的前面,可以给集合建立索引,来提高处理数据的效率。
  • 可以用 match、limit、$skip 对文档进行提前过滤,以减少后续处理文档的数量。

当聚合管道执行命令时,MongoDB 也会对各个阶段自动进行优化,主要包括以下几个情况:

  1. sort + match 顺序优化 如果 match 出现在 sort 之后,优化器会自动把 match 放到 sort 前面
  2. skip + limit 顺序优化 如果 skip 在 limit 之后,优化器会把 limit 移动到 skip 的前面,移动后 limit的值等于原来的值加上 skip 的值。 例如:移动前:{skip: 10, limit: 5},移动后:{limit: 15, skip: 10}
8.1.4 聚合管道使用限制

对聚合管道的限制主要是对 返回结果大小 和 内存 的限制。

返回结果大小

聚合结果返回的是一个文档,不能超过 16M,从 MongoDB 2.6版本以后,返回的结果可以是一个游标或者存储到集合中,返回的结果不受 16M 的限制。

内存

聚合管道的每个阶段最多只能用 100M 的内存,如果超过100M,会报错,如果需要处理大数据,可以使用 allowDiskUse 选项,存储到磁盘上。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 8. MongoDB 聚合
    • 8.1 聚合管道
      • 8.1.1 阶段操作符
      • 8.1.1 阶段操作符
      • 8.1.2 表达式操作符
      • 集合操作(Set Operators)
      • 比较聚合操作(Comparison Aggregation Operators)
      • 算术聚合操作(Arithmetic Aggregation Operators)
      • 字符串聚合操作(String Aggregation Operators)
      • 数组聚合操作(Array Aggregation Operators)
      • 日期聚合操作(Date Aggregation Operators)
      • 条件聚合操作(Conditional Aggregation Operators)
      • 数据类型聚合操作(Data Type Aggregation Operators)
      • 8.1.3 聚合管道优化
      • 8.1.4 聚合管道使用限制
相关产品与服务
云数据库 MongoDB
腾讯云数据库 MongoDB(TencentDB for MongoDB)是腾讯云基于全球广受欢迎的 MongoDB 打造的高性能 NoSQL 数据库,100%完全兼容 MongoDB 协议,支持跨文档事务,提供稳定丰富的监控管理,弹性可扩展、自动容灾,适用于文档型数据库场景,您无需自建灾备体系及控制管理系统。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com