我在将简单的.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" }
我的问题是:
.aggregate()
给出的结果顺序不同于.find().sort().limit()
?.aggregate()
的结果顺序取决于$limit
的值?所有这些文档都具有相同的sortField
值,因此顺序不是确定性的。在_id
上添加辅助排序以确保一致的结果。
db.SomeCollection.aggregate([{$sort: {"sortField": 1, _id: 1}}, {$limit: 5}]);