mongodb - 从包含约 120 万条记录的集合中,Mongo 查找查询失败
问题描述
有 2 个集合:Alerts和AlertTypes。Alerts集合有一个名为:alertTypeId的字段,它是AlertTypes集合的查找/外键。
我需要优化以下查询,通过加入相应的集合从Alerts集合中获取数据以及 AlertType 名称。
我使用聚合函数如下:
db.Alerts.aggregate([{
"$match": {
"status": {
"$ne": -1
},
"type": 4
}
}, {
"$lookup": {
"localField": "alertTypeId",
"from": "AlertTypes",
"foreignField": "_id",
"as": "alertTypeRel"
}
}, {
"$project": {
"title": 1,
"type": 1,
"alertTypeId": 1,
"alertTypeRel.alertTypeName": 1,
"priority": 1,
"message": 1,
"status": 1,
"startDate": 1,
"createdAt": 1,
"createdBy": 1,
"validUntil": 1,
"errorFlag": 1,
"extApiId": 1,
"errorMessage": 1,
"autoPublish": 1,
"statusChangedBy": 1
}
},{
"$sort": {
"status": 1,
"createdAt": -1
}
}, {
"$group": {
"_id": null,
"count": {
"$sum": 1
},
"results": {
"$push": "$$ROOT"
}
}
}, {
"$project": {
"total": "$count",
"_id": 0,
"results": {
"$slice": ["$results", 0, 10]
}
}
}], {
"collation": {
"locale": "en",
"strength": 2
},
"allowDiskUse": true,
"cursor": {}
}).pretty();
我也索引了这些字段。例如:
{
"v" : 2,
"key" : {
"status" : 1,
"createdAt" : -1
},
"name" : "status_1_createdAt_-1"
}
Alerts和AlertTypes集合中分别有 1 250 543 和 117 条记录。我也尝试了facet
查询,但也抛出了以下相同的结果:
uncaught exception: Error: command failed: {
"ok" : 0,
"errmsg" : "$push used too much memory and cannot spill to disk. Memory limit: 104857600 bytes",
"code" : 146,
"codeName" : "ExceededMemoryLimit"
} : aggregate failed :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
doassert@src/mongo/shell/assert.js:18:14
_assertCommandWorked@src/mongo/shell/assert.js:639:17
assert.commandWorked@src/mongo/shell/assert.js:729:16
DB.prototype._runAggregate@src/mongo/shell/db.js:266:5
DBCollection.prototype.aggregate@src/mongo/shell/collection.js:1058:12
@(shell):1:1
谢谢
解决方案
阶段在$group
推送对象时使用了太多内存$$ROOT
,修复很少,只需使用和阶段$facet
代替,$group
$project
- 对于您可以使用的分页
$skip
和$limit
阶段, - 对于计数总文档使用
$count
运算符 $facet
将两者分开result
并且count
- 使用
$lookup
after$limit
stage 因为我们要获取 10 个文档,并且只需要查找 10 个文档 $project
如果需要,在查找后使用
你最后的查询是,
db.Alerts.aggregate([
{
"$match": {
"status": { "$ne": -1 },
"type": 4
}
},
{
"$sort": {
"status": 1,
"createdAt": -1
}
},
{
$facet: {
result: [
{ $skip: 0 },
{ $limit: 10 },
{
"$lookup": {
"localField": "alertTypeId",
"from": "AlertTypes",
"foreignField": "_id",
"as": "alertTypeRel"
}
},
{
"$project": {
"title": 1,
"type": 1,
"alertTypeId": 1,
"alertTypeRel.alertTypeName": 1,
"priority": 1,
"message": 1,
"status": 1,
"startDate": 1,
"createdAt": 1,
"createdBy": 1,
"validUntil": 1,
"errorFlag": 1,
"extApiId": 1,
"errorMessage": 1,
"autoPublish": 1,
"statusChangedBy": 1
}
}
],
count: [{ $count: "total" }]
}
}
],
{
"collation": {
"locale": "en",
"strength": 2
},
"allowDiskUse": true,
"cursor": {}
})
.pretty();
- 为了获得更高的性能,您可以在匹配条件字段和排序字段上使用索引,根据您的查询使用可以使用复合索引
status
,type
并createdAt
查看有关复合索引的更多详细信息
此查询未经测试!
推荐阅读
- node.js - 在 Buffer 对象上使用十六进制编码时出现意外结果
- amazon-s3 - 在pulumi创建桶后添加s3桶生命周期规则
- python - 如何在 python tkinter 中将小部件居中?
- java - 在 JFrame 中围绕屏幕环绕移动文本
- python-3.x - 在 ProcessPoolExecutor 中显示正在运行的执行程序标识
- java - 从 Jar 加载 STv4 模板
- c - Makefile 编译和链接问题
- c++ - C++ 转一个 std::tuple
进入 std::string? - python - Discord-Bot 仅将一个命令发送到正确的通道,但所有其他命令都发送到错误的通道
- android - 如何调整我的 Camera2 API 设置以匹配库存相机应用程序的质量?