从排序结果中获取文档 ID 之前的 MongoDB 中的 N 个文档

问题描述 投票:0回答:2

我在 MongoDB 中有一个集合,如下所示。 -> Mongo Playground 链接

我已按概述和 ID 对集合进行了排序。

$sort{{ overview: 1,_id:1 }}

这会产生这样的集合。

当我过滤集合以仅显示“主题 13”之后的文档时,它按预期工作。

$match{{
  _id:{$gt:ObjectId('605db89d208db95eb4878556')}
}}

但是,当我尝试使用“主题 13”之前的文档(即“主题 6”)并使用以下查询时,它无法按我的预期工作。

$match{{
      _id:{$lt:ObjectId('605db89d208db95eb4878556')}
    }}

结果中我得到的不是“主题 6”,而是以下内容。

我怀疑这种情况正在发生,因为 mongodb 总是在排序之前过滤文档,无论聚合管道中的顺序如何。

请建议我一种在 mongodb 中获取特定“_id”之前的文档的方法。

我的集合中有 600 个文档,这是一个示例数据集。下面是我的完整聚合查询。

[
  {
    '$sort': {
      'overview': 1, 
      '_id': 1
    }
  }, {
    '$match': {
      '_id': {
        '$lt': new ObjectId('605db89d208db95eb4878556')
      }
    }
  }
]
mongodb pagination mongodb-query
2个回答
0
投票

MongoDB 通过将排序移动到您的情况的末尾来优化查询性能,因为您已经

$sort
后跟
$match

https://docs.mongodb.com/manual/core/aggregation-pipeline-optimization/#sort-match-sequence-optimization

当您有一个 $sort 后跟 $match 的序列时,$match 会移动到 $sort 之前,以最大限度地减少要排序的对象数量。例如,如果管道由以下阶段组成:

[
  { '$sort': { 'overview': 1, '_id': 1 }  },
  { '$match': { '_id': { '$lt': new ObjectId('605db89d208db95eb4878556') } }
]

在优化阶段,优化器将序列转换为以下形式:

[
    { '$match': { '_id': { '$lt': new ObjectId('605db89d208db95eb4878556') } },
    { '$sort': { 'overview': 1, '_id': 1 } }
]

查询计划器结果 -

我们可以看到,在执行排序之后,第一阶段是匹配查询。

{
    "stages" : [ 
        {
            "$cursor" : {
                "query" : {
                    "_id" : {
                        "$lt" : ObjectId("605db89d208db95eb4878556")
                    }
                },
                "queryPlanner" : {
                    "plannerVersion" : 1,
                    "namespace" : "video.data3",
                    "indexFilterSet" : false,
                    "parsedQuery" : {
                        "_id" : {
                            "$lt" : ObjectId("605db89d208db95eb4878556")
                        }
                    },
                    "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "_id" : 1
                            },
                            "indexName" : "_id_",
                            "isMultiKey" : false,
                            "multiKeyPaths" : {
                                "_id" : []
                            },
                            "isUnique" : true,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 2,
                            "direction" : "forward",
                            "indexBounds" : {
                                "_id" : [ 
                                    "[ObjectId('000000000000000000000000'), ObjectId('605db89d208db95eb4878556'))"
                                ]
                            }
                        }
                    },
                    "rejectedPlans" : []
                }
            }
        }, 
        {
            "$sort" : {
                "sortKey" : {
                    "overview" : 1,
                    "_id" : 1
                }
            }
        }
    ],
    "ok" : 1.0
}

0
投票

在 MongoDB v5.0+ 中,您可以使用

$setWindowFields
通过
$push
和 ["unbounded", -1] 的文档窗口来获取某个文档之前的所有文档

db.collection.aggregate([
  {
    "$setWindowFields": {
      "partitionBy": "$state",
      "sortBy": {
        "overview": 1,
        "_id": 1
      },
      "output": {
        "docsBefore": {
          "$push": "$$ROOT",
          "window": {
            "documents": [
              "unbounded",
              -1
            ]
          }
        }
      }
    }
  },
  {
    "$match": {
      "_id": ObjectId("605db89d208db95eb4878556")
    }
  }
])

蒙戈游乐场

© www.soinside.com 2019 - 2024. All rights reserved.