在这里,我刚刚创建了9个文档{id,name}的集合。 所有文档的名称字段具有相同的值“ A”。
[
{
"name": "A",
"id": 1
},
{
"name": "A",
"id": 2
},
{
"name": "A",
"id": 3
},
{
"name": "A",
"id": 4
},
{
"name": "A",
"id": 5
},
{
"name": "A",
"id": 6
},
{
"name": "A",
"id": 7
},
{
"name": "A",
"id": 8
},
{
"name": "A",
"id": 9
}
]
我想在按名称排序后对这个集合进行分页(在我的情况下按名称排序是没有用的,但是我点了一下以证明奇怪的行为),3乘3。(页面大小是3)。
当我使用$ skip 0,$ limit 3(第一页)执行聚合管道时:
db.collection.aggregate([
{
"$sort": {
"name": 1
}
},
{
"$skip": 0
},
{
"$limit": 3
}
])
结果是:
[
{
"_id": ObjectId("5a934e000102030405000000"),
"id": 1,
"name": "A"
},
{
"_id": ObjectId("5a934e000102030405000001"),
"id": 2,
"name": "A"
},
{
"_id": ObjectId("5a934e000102030405000002"),
"id": 3,
"name": "A"
}
]
现在,当我想获取以下页面($ skip 3,$ limit 3)时,结果是:
[
{
"_id": ObjectId("5a934e000102030405000000"),
"id": 1,
"name": "A"
},
{
"_id": ObjectId("5a934e000102030405000002"),
"id": 3,
"name": "A"
},
{
"_id": ObjectId("5a934e000102030405000005"),
"id": 6,
"name": "A"
}
]
我们注意到ID为1和3的文档再次被提取。最终会出现错误的分页(重复)!
当对非唯一列进行排序导致这种奇怪的行为时,您如何解释呢?
答案 0 :(得分:0)
运行时:排序->跳过(3)->限制(3)
Mongo查询优化器将查询顺序更改为: sort + limit(6)-> skip(3)
因此,mongo正在使用值为“ limit + skip”的“ limit”。排序和限制不是两个不同的阶段,而是一个阶段。而且进行此查询优化的原因是,找到最大的6个元素并对其进行排序比先进行全部排序并获得前6个元素要好
因此发生这种奇怪的行为。证明说明结果:
{
"stages" : [
{
"$cursor" : {
"query" : {},
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "5ceb96f75538551e7d3bcdb8_lav.test",
"indexFilterSet" : false,
"parsedQuery" : {},
"winningPlan" : {
"stage" : "COLLSCAN",
"direction" : "forward"
},
"rejectedPlans" : []
}
}
},
{
"$sort" : {
"sortKey" : {
"name" : 1
},
"limit" : NumberLong(6)
}
},
{
"$skip" : NumberLong(3)
}
],
"ok" : 1.0,
"operationTime" : Timestamp(1560596833, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1560596835, 4),
"signature" : {
"hash" : { "$binary" : "ouhjbA5FjqF/EE4ySVpHdvG8HaM=", "$type" : "00" },
"keyId" : NumberLong(6691284195030859777)
}
}
}
在名称字段上添加索引,排序将变为稳定排序。这样您将获得理想的结果。