【问题标题】:MongoDB value of $limit after $sort changes the order of results in aggregate$sort 更改聚合结果顺序后 $limit 的 MongoDB 值
【发布时间】:2018-09-20 18:25:57
【问题描述】:

我在将简单的.find().sort().skip().limit() 迁移到聚合框架时遇到了问题,导致分页中断:同一个文档出现在多个页面上。最后,我意识到$limit 会影响$sort 的结果的顺序。下面我将描述如何重现查看问题的步骤(在 Mongo 3.4.17 和 3.6.7 上检查)。

> // 1. Create a simple coleection and fill it with test data: 
> for(var i = 0; i < 10; ++i) db.SomeCollection.insert({sortField: "just_some_string"});
> db.SomeCollection.count();
10
>
> // 2. Check, that with .find().sort().limit() the order of results does not depend on the `limit()`'s value:
db.SomeCollection.find().sort({"sortField": 1}).limit(5)
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb531"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb532"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb533"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb534"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb535"), "sortField" : "just_some_string" }
> db.SomeCollection.find().sort({"sortField": 1}).limit(8)
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb531"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb532"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb533"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb534"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb535"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb536"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb537"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb538"), "sortField" : "just_some_string" }
>
> // 3. Logically the same query but using Aggregation Framework
> db.SomeCollection.aggregate([{$sort: {"sortField": 1}}, {$limit: 5}]);
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb534"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb535"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb532"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb531"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb533"), "sortField" : "just_some_string" }
> db.SomeCollection.aggregate([{$sort: {"sortField": 1}}, {$limit: 8}]);
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb538"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb535"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb532"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb534"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb536"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb531"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb533"), "sortField" : "just_some_string" }
{ "_id" : ObjectId("5ba3ddf3a07260b77dddb537"), "sortField" : "just_some_string" }

我的问题是:

  1. 为什么 .aggregate() 与 $sort 后跟 $limit 给出的结果顺序与 .find().sort().limit() 不同?
  2. 为什么.aggregate() 中的结果顺序取决于$limit 的值?

【问题讨论】:

    标签: mongodb aggregation-framework


    【解决方案1】:

    所有这些文档都具有相同的sortField 值,因此顺序不是确定性的。在_id 上添加二级排序以保证结果一致。

    db.SomeCollection.aggregate([{$sort: {"sortField": 1, _id: 1}}, {$limit: 5}]);
    

    【讨论】:

    • 您的意思是.find().sort().limit() 隐式按_id 排序吗?
    • 不,除非您在 _id 上添加二级排序,否则 find 也可能以不同的顺序返回它们。
    • 但是find 确实没有不同的结果顺序取决于limitaggregate 有。 MongoDB 的文档说,当sortlimit 一起使用时,两者都使用top-k。此外,在我的实际应用程序中,我有一个匹配索引的过滤条件,find 的结果仍然是可预测的,它们的顺序不依赖于limit
    • 碰巧不同的$limit 值会触发aggregate 的不同排序,而find 则不会。但该顺序仍然完全有效,这就是为什么您需要包含二级排序以保证一致的结果。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-15
    • 2015-01-25
    • 1970-01-01
    • 2015-11-10
    • 2019-05-03
    相关资源
    最近更新 更多