跳到主要内容

聚合搜索

聚合主要用来处理数据(统计平均值,求和等)并返回计算后的数据结果。

流水线/管道

聚合是一个流水线式的批处理作业,初始文档经过多个阶段的流水线处理后,得到转换后的聚合结果。

假设已有一个集合 books,其中包含以下格式记录:

[
{
"_id": "xxx",
"category": "Novel",
"name": "The Catcher in the Rye",
"onSale": true,
"sales": 80
}
]

聚合示例如下:

// 云函数端示例
const cloudbase = require("@cloudbase/node-sdk")
const app = cloudbase.init()
const db = app.database()
const $ = db.command.aggregate

exports.main = async (event, context) => {
const res = await db.collection('books').aggregate()
.match({
onSale: true // 是否正在出售
})
.group({
// 按 category 字段分组
_id: '$category',
// 让输出的每组记录有一个 avgSales 字段,其值是组内所有记录的 sales 字段的平均值
avgSales: $.avg('$sales')
})
.end()
return {
res
}
}

第一阶段:match 阶段过滤出了集合中的文档数据(onSale:true 表示找出正在出售的书籍)并传给下一个阶段。

第二阶段:group 阶段基于 category 字段进行分组,并统计出每组中所有记录的 sales 字段平均值。

API 及操作符

参考 Node.js SDK API 文档,一览所有的聚合阶段 API操作符

优化执行

利用索引

matchsort 如果是在流水线的开头的话是可以利用索引的。geoNear 也可以利用地理位置索引,但要注意的是,geoNear 必须是流水线的第一个阶段。

尽早缩小数据集

在不需要集合的全集情况下,应该尽早的通过 matchlimitskip 缩小要处理的记录数量。

注意事项

除了 match 阶段,在各个聚合阶段中传入的对象中,可使用的操作符都是聚合操作符,需要特别注意的是,match 进行的是查询匹配,因此语法同普通查询 where 的语法,用的是普通查询操作符。

FAQ

Sort exceeded memory limit of 104857600 bytes

{"Error":{"Code":"FailedOperation","Message":"(Location16820) Sort exceeded memory limit of 104857600 bytes, but did not opt in to external sorting. Aborting operation. Pass allowDiskUse:true to opt in."},"RequestId":"1728459320973_0.7685102267589137_33591173-19270342dd4_15"}

mongo sort 排序内存溢出问题。

解决方案

  1. 合理使用project,使用更小的数据集进行排序。
  2. 合理使用sort,减少排序字段的数量。
  3. 合理使用match, 尽量在match后,或者最后进行sort。
  4. 合理使用索引,使用索引进行排序(如果可能的话)。