首页 > 解决方案 > 根据可能不存在的字段查询和排序mongo中的大量数据

问题描述

我对 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"
                }
            ]
        }
    }
]

关于数据的一些观察:

我想要实现的是让文档按该status字段排序,这就像一个枚举,它可以有 3 个值-ACTIVE和.PENDINGREJECTED

我试图通过使用如下所示的聚合来实现这一点:

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错误消息。

所以我的问题是:

  1. 是否有更快的替代方案,无论是否有聚合?
  2. allowDiskUse在进行聚合时使用该选项是否有任何风险?
  3. 改变一点文档结构并将该可排序字段添加到文档的根目录,为其添加索引并使用它会更好(或者它是“mongo”方式).sort({"statusField": 1})吗?这将是最后的选择,因为我必须迁移现有数据。

标签: mongodbmongodb-queryprojection

解决方案


sortStatus可以使用以下方法获得您的字段值:

{ $addFields: { sortStatus: { $ifNull: [ "$stored.box.status", "$checked.box.status" ] } } },

这会使查询更快吗?不,但代码更简单。


(1) 是否有更快的替代方案,无论是否有聚合?

我不知道,现在。


(2) 聚合时使用allowDiskUse选项有什么风险吗?

使用该allowDiskUse:true选项意味着当此操作的内存 (RAM) 超过其限制时,排序操作会使用磁盘获取额外资源。与内存相比,磁盘 IO非常慢,因此“风险”是慢得多的排序操作。当排序操作需要的内存超过 100MB 的限制时,此选项变为必需(请参阅有关聚合中的排序和内存限制的文档)。


(3)改变一点文档结构并将可排序字段添加到文档的根目录,为其添加索引并使用 .sort({"statusField “:1})?这将是最后的选择,因为我必须迁移现有数据。

创建新的状态字段和在该字段上的索引意味着新的考虑:

  • 创建一个新字段“状态”需要在编写文档时进行额外的计算(也可能在更新期间)。
  • 在这个新字段上创建索引也是写入期间的额外开销。请注意,索引大小会随着文档数量的增加而变大。

这些会影响应用程序的写入性能。

但是,查询将变成一个简单的排序。在集合中有大量文档的情况下,用于排序的索引在操作期间可能适合内存,也可能不适合内存。如果没有一些实际试验,您无法确定此选项如何提供帮助。

这是有关索引策略的一些文档。


推荐阅读