Docs 菜单
Docs 主页
/ /
Atlas App Services
/ /

在 MongoDB Atlas 中聚合数据 — 函数

在此页面上

  • Overview
  • 数据模型
  • 运行聚合管道
  • 使用 Atlas Search 查找数据
  • 聚合阶段
  • 筛选文档
  • 对文档分组
  • 项目文档字段
  • 向文档添加字段
  • Unwind Array Values

本页上的示例演示了如何在函数中使用 MongoDB 查询 API 来聚合 Atlas 集群中的文档。

MongoDB 聚合管道通过一系列数据聚合阶段运行集合中的所有文档,这些阶段允许您对文档进行过滤和调整,以及收集有关相关文档组的摘要数据。

注意

支持的聚合阶段

Atlas App Services 支持几乎所有 MongoDB 聚合管道阶段和操作符,但某些阶段和操作符必须在系统函数中执行。有关更多信息,请参阅聚合框架限制

此页面上的示例使用名为 store.purchases 的集合,其中包含有关在线商店中的历史商品销售的信息。每个文档包含已购买的 items 的列表,其中包括每一商品的 name 和所购 quantity 以及已购买这些商品的客户的唯一 ID 值。

{
"title": "Purchase",
"required": ["_id", "customerId", "items"],
"properties": {
"_id": { "bsonType": "objectId" },
"customerId": { "bsonType": "objectId" },
"items": {
"bsonType": "array",
"items": {
"bsonType": "object",
"required": ["name", "quantity"],
"properties": {
"name": { "bsonType": "string" },
"quantity": { "bsonType": "int" }
}
}
}
}
}

要在函数中使用代码片段,您必须先实例化一个 MongoDB 集合句柄:

exports = function() {
const mongodb = context.services.get("mongodb-atlas");
const itemsCollection = mongodb.db("store").collection("items");
const purchasesCollection = mongodb.db("store").collection("purchases");
// ... paste snippet here ...
}

可以使用 collection.aggregate() 方法执行聚合管道。

以下函数代码片段按 purchases 集合中的所有文档的 customerId 值对其进行分组,并汇总每个客户购买的商品数量以及他们进行的购买总数。对文档进行分组后,管道将一个新字段添加到每个客户的文档中,该字段计算每个客户一次购买的平均商品数量 averageNumItemsPurchased

const pipeline = [
{ "$group": {
"_id": "$customerId",
"numPurchases": { "$sum": 1 },
"numItemsPurchased": { "$sum": { "$size": "$items" } }
} },
{ "$addFields": {
"averageNumItemsPurchased": {
"$divide": ["$numItemsPurchased", "$numPurchases"]
}
} }
]
return purchasesCollection.aggregate(pipeline).toArray()
.then(customers => {
console.log(`Successfully grouped purchases for ${customers.length} customers.`)
for(const customer of customers) {
console.log(`customer: ${customer._id}`)
console.log(`num purchases: ${customer.numPurchases}`)
console.log(`total items purchased: ${customer.numItemsPurchased}`)
console.log(`average items per purchase: ${customer.averageNumItemsPurchased}`)
}
return customers
})
.catch(err => console.error(`Failed to group purchases by customer: ${err}`))

您可以使用 和collection.aggregate() 聚合阶段在集合上运行 Atlas Search$search 查询。

重要

App Services 以系统用户身份执行 $search 操作,并对返回的搜索结果强制执行字段级规则。这意味着用户可以搜索他们没有读取权限的字段。在这种情况下,搜索基于指定字段,但返回的文档不包括该字段。

exports = async function searchMoviesAboutBaseball() {
// 1. Get a reference to the collection you want to search.
const movies = context.services
.get("mongodb-atlas")
.db("sample_mflix")
.collection("movies");
// 2. Run an aggregation with $search as the first stage.
const baseballMovies = await movies
.aggregate([
{
$search: {
text: {
query: "baseball",
path: "plot",
},
},
},
{
$limit: 5,
},
{
$project: {
_id: 0,
title: 1,
plot: 1,
},
},
])
.toArray();
return baseballMovies;
};
{
"plot" : "A trio of guys try and make up for missed
opportunities in childhood by forming a three-player
baseball team to compete against standard children
baseball squads.",
"title" : "The Benchwarmers"
}
{
"plot" : "A young boy is bequeathed the ownership of a
professional baseball team.",
"title" : "Little Big League"
}
{
"plot" : "A trained chimpanzee plays third base for a
minor-league baseball team.",
"title" : "Ed"
}
{
"plot" : "The story of the life and career of the famed
baseball player, Lou Gehrig.",
"title" : "The Pride of the Yankees"
}
{
"plot" : "Babe Ruth becomes a baseball legend but is
unheroic to those who know him.",
"title" : "The Babe"
}

注意

$$SEARCH_META 变量可用性

$$SEARCH_META聚合变量仅适用于作为系统运行的函数,或者搜索集合上的第一个角色将其apply_whenread表达式设立为true的函数。

如果这两种情况都不存在,则 $$SEARCH_META 未定义,聚合将失败。

您可以使用$match阶段,使用标准MongoDB查询语法过滤传入文档。

{
"$match": {
"<Field Name>": <Query Expression>,
...
}
}

例子

以下 $match 阶段筛选传入文档,以便仅包含 graduation_year 字段的值介于 20192024(含)之间的文档。

{
"$match": {
"graduation_year": {
"$gte": 2019,
"$lte": 2024
},
}
}

您可以使用$ 群组阶段聚合一个或多个文档群组的摘要数据。 MongoDB根据_id表达式对文档进行分组。

注意

可以通过在字段名称前添加 $ 前缀来引用特定文档字段。

{
"$group": {
"_id": <Group By Expression>,
"<Field Name>": <Aggregation Expression>,
...
}
}

例子

以下 $group 阶段按文档的 customerId 字段的值对文档进行分组,并计算每个 customerId 出现的采购文档的数量。

{
"$group": {
"_id": "$customerId",
"numPurchases": { "$sum": 1 }
}
}

您可以使用$ 项目阶段包含或省略文档中的特定字段,或使用聚合操作符计算新字段。 要包含字段,请将其值设立为1 。 要省略字段,请将其值设立为0

注意

不能同时省略和包含 _id 以外的字段。如果显式包含 _id 以外的字段,则未显式包含的任何字段都将被自动省略(反之亦然)。

{
"$project": {
"<Field Name>": <0 | 1 | Expression>,
...
}
}

例子

以下 $project 阶段省略了 _id 字段,包括 customerId 字段并创建了一个名为 numItems 的新字段,其值是 items 数组中的文档数:

{
"$project": {
"_id": 0,
"customerId": 1,
"numItems": { "$sum": { "$size": "$items" } }
}
}

您可以在$addFields阶段通过聚合操作符添加具有计算值的新字段。

注意

$addFields$project 类似,但不允许包含或省略字段。

例子

以下 $addFields 阶段创建了一个名为 numItems 的新字段,其值是 items 数组中的文档数:

{
"$addFields": {
"numItems": { "$sum": { "$size": "$items" } }
}
}

您可以使用 $unwind 阶段来聚合数组字段的各个元素。当您展开数组字段时,MongoDB 会为该数组字段的每个元素复制每个文档一次,但同时还会在每个副本中用数组元素替换数组值。

{
$unwind: {
path: <Array Field Path>,
includeArrayIndex: <string>,
preserveNullAndEmptyArrays: <boolean>
}
}

例子

下面的 $unwind 阶段为每个文档中 items 数组的每个元素创建一个新文档。该阶段还会在每个新文档中添加一个名为 itemIndex 的字段,指定元素在原始数组中的位置索引:

{
"$unwind": {
"path": "$items",
"includeArrayIndex": "itemIndex"
}
}

请考虑 purchases 集合中的以下文档:

{
_id: 123,
customerId: 24601,
items: [
{ name: "Baseball", quantity: 5 },
{ name: "Baseball Mitt", quantity: 1 },
{ name: "Baseball Bat", quantity: 1 },
]
}

如果我们将示例 $unwind 阶段应用于此文档,该阶段将输出以下三个文档:

{
_id: 123,
customerId: 24601,
itemIndex: 0,
items: { name: "Baseball", quantity: 5 }
}, {
_id: 123,
customerId: 24601,
itemIndex: 1,
items: { name: "Baseball Mitt", quantity: 1 }
}, {
_id: 123,
customerId: 24601,
itemIndex: 2,
items: { name: "Baseball Bat", quantity: 1 }
}

后退

写入