【发布时间】:2019-12-05 20:14:40
【问题描述】:
我对 mongo 比较陌生,我有一个如下所示的集合:
[
{
"stored": {
"box": [
{
"parcelId": "uwb1",
"status": "ACTIVE"
}
]
},
"checked": {
"box": [
{
"parcelId": "uwb1",
"status": "ACTIVE"
}
]
}
},
{
"stored": {
"box": [
{
"parcelId": "aqrf123",
"status": "PENDING"
}
]
},
"checked": {
"box": [
{
"parcelId": "aqrf123",
"status": "PENDING"
}
]
}
},
{
"checked": {
"box": [
{
"parcelId": "zuz873",
"status": "ACTIVE"
}
]
}
}
]
关于数据的一些观察:
- 文档将始终包含
checked字段,但可能没有stored字段 -
checked和stored字段具有相同的架构 - 两者都将始终具有
box字段,我们可以假设box字段将始终在数组中具有 1 个元素(只有 1 个,不多也不少) - 此集合中的文档数量相对较高(约 1 亿)
我想要实现的目标是让文档按 status 字段排序,这就像一个枚举,它可以有 3 个值 - ACTIVE、PENDING和REJECTED。
- 如果对于文档,
stored字段存在,我将从那里获取它并忽略checked字段。 - 否则我将不得不从
checked字段中获取它,如前所述,该字段保证存在。 - 一个重要的要求是将整个文档返回给消费者/客户端,所以我不能使用
projection来减少来自文档的数据量(这可能会使整个操作更快)。
我如何尝试实现这是通过使用如下所示的聚合:
db.getCollection('entries')
.aggregate([{
$addFields: {
sortStatus: {
$ifNull: [{
$let: {
vars: {
box: {
$arrayElemAt: [
"$stored.box", 0
]
}
},
in: "$$box.status"
}
}, {
$let: {
vars: {
box: {
$arrayElemAt: [
"$checked.box", 0
]
}
},
in: "$$box.status"
}
}]
}
}
},
{
$sort: {
sortStatus: 1
}
}
], {
allowDiskUse: true
})
这似乎可以完成这项工作,但感觉很慢。还有allowDiskUse,这让我有点不舒服。如果我忽略它,我会收到 Sort exceeded memory limit of x bytes, but did not opt in to external sorting. Aborting operation. Pass allowDiskUse:true to opt in 错误消息。
所以我的问题是:
- 是否有更快的替代方案,不管是聚合还是不聚合?
- 在进行聚合时使用
allowDiskUse选项是否有任何风险? - 改变一点文档结构并将该可排序字段添加到文档的根目录,为其添加索引并使用
.sort({"statusField": 1})会更好(或者它是“mongo”方式)吗?这将是最后的选择,因为我必须迁移现有数据。
【问题讨论】:
标签: mongodb mongodb-query projection