Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/extjs/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mongodb 按可能不存在的字段查询和排序mongo中的大量数据_Mongodb_Mongodb Query_Projection - Fatal编程技术网

Mongodb 按可能不存在的字段查询和排序mongo中的大量数据

Mongodb 按可能不存在的字段查询和排序mongo中的大量数据,mongodb,mongodb-query,projection,Mongodb,Mongodb Query,Projection,我对mongo比较陌生,我有一个类似这样的收藏: [ { "stored": { "box": [ { "parcelId": "uwb1", "status": "ACTIVE" } ] }, "checked": { "bo

我对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"
                }
            ]
        }
    }
]
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
    })
关于数据的一些观察结果:

  • 文档将始终选中
    字段,但可能没有存储
    字段
  • 选中的
    和存储的
    字段具有相同的架构
  • 两者都将始终有
    字段,我们可以假设
    字段在数组中始终有1个元素(仅1个,不多,不少)
  • 此集合中的文档数量相对较高(约1亿)
我试图实现的是按照
状态
字段对文档进行排序,该字段类似于一个枚举,它可以有3个值-
活动
待定
拒绝

  • 如果文档中存在
    存储的
    字段,我将从那里获取它,并忽略
    选中的
    字段
  • 否则,我将不得不从
    checked
    字段中获取它,正如前面提到的,它保证存在
  • 一个重要的要求是将整个文档返回给消费者/客户机,因此我不能使用
    projection
    来减少文档中的数据量(这可能会使整个操作更快)
我是如何通过使用一个如下所示的聚合来实现这一点的:

[
    {
        "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"
                }
            ]
        }
    }
]
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
,这让我有点不舒服。如果我不使用它,我得到的
排序超过了x字节的内存限制,但没有选择外部排序。正在中止操作。Pass allowDiskUse:选择加入时为true
错误消息

所以我的问题是:

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

  • 您的
    sortStatus
    字段值可以通过以下方式获得:

    { $addFields: { sortStatus: { $ifNull: [ "$stored.box.status", "$checked.box.status" ] } } },
    
    这会使查询更快吗?没有,但是代码更简单


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

    我不知道,此刻


    (2) 在执行任务时使用allowDiskUse选项是否存在任何风险 聚合

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


    (3) 改变一点是不是更好(或者是“mongo”方式) 文档结构,并将该可排序字段添加到 文档,为它添加一个索引,然后只使用.sort({“statusField”:1})? 这将是最后的选择,因为我必须迁移 现有数据

    在该字段上创建新的状态字段和索引意味着新的注意事项:

    • 创建新字段“status”需要在 编写文档的时间(也可能在更新期间)
    • 在这个新字段上创建索引也是写入期间的额外开销。注意,由于文档数量较多,索引大小将较大
    这些可能会影响应用程序的写入性能

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


    这是一些关于的文档。

    我明白了,谢谢你的详细回答。由于
    allowDiskUse
    而变慢并不是一个破坏交易的因素,我担心的是不会导致任何问题/致命错误。事实上,选项(3)似乎更令人头痛。