And*_*ine 4 sorting pagination mongodb
如何对按非唯一字段排序的查询进行分页?例如,集合中的文档可能是(按s:1排序,然后是_id:-1):
{_id: 19, s: 3},
{_id: 17, s: 3},
{_id: 58, s: 4},
// etc...
Run Code Online (Sandbox Code Playgroud)
有一个简单的限制/跳过方法可以......慢慢地工作.
是否可以使用以下内容:
db.collection.find()
.sort({s:1, _id:-1})
.min({s:3, _id:17}) // this does not work as wanted!
.limit(2);
Run Code Online (Sandbox Code Playgroud)
检索
{_id: 17, s: 3},
{_id: 58, s: 4}
Run Code Online (Sandbox Code Playgroud)
?
如果您想通过"页码"进行分页那么你是非常坚持的.limit()和.skip()后你对你的关键结果进行排序采用的方法.您可能已经做了一些阅读并发现它"效率不高",主要是因为"跳过""n"结果以达到某个页面的成本.
但是你需要它的原则是合理的:
db.collection.find().sort({ "s": -1, "_id": 1 }).skip(<page-1>).limit(<pageSize>)
Run Code Online (Sandbox Code Playgroud)
如果您只需要在分页中"向前"移动,则可以使用更快的替代方法,也可以使用"已排序"的结果.
关键是要保持对"s"的"最后看到"值的引用,然后通常是_id值列表,直到"s"的值发生变化.所以使用一些文档进行演示,这些文档已经过分类以用于演示目的:
{ "_id": 1, "s": 3 },
{ "_id": 2, "s": 3 },
{ "_id": 3, "s": 3 },
{ "_id": 4, "s": 2 },
{ "_id": 5, "s": 1 },
{ "_id": 6, "s": 1 },
Run Code Online (Sandbox Code Playgroud)
为了获得"两个"结果的"第一页",您的第一个查询很简单:
db.collection.find().sort({ "s": -1, "_id": 1}).limit(2)
Run Code Online (Sandbox Code Playgroud)
但是按照这样处理文件:
var lastVal = null,
lastSeen = [];
db.collection.find().sort({ "s": -1, "_id": 1}).limit(2).forEach(function(doc) {
if ( doc.s != lastVal ) { // Change when different
lastVal = doc.s;
lastSeen = [];
}
lastSeen.push(doc._id); // Push _id onto array
// do other things like output
})
Run Code Online (Sandbox Code Playgroud)
因此,在第一次迭代时,lastVal值将是3,并且lastSeen将包含_id数组中的两个文档值[1,2].这些东西你会存储在等待下一页请求的用户会话数据中.
根据您对下一页设置的请求,您发出如下:
var lastVal = 3,
lastSeen = [1,2];
db.collection.find({
"_id": { "$nin": lastSeen },
"s": { "$lte": lastVal }
}).sort({ "s": -1, "_id": 1}).limit(2).forEach(function(doc) {
if ( doc.s != lastVal ) { // Change when different
lastVal = doc.s;
lastSeen = [];
}
lastSeen.push(doc._id); // Push _id onto array
// do other things like output
})
Run Code Online (Sandbox Code Playgroud)
这要求"s"的选择需要从记录的"小于或等于"(因为排序的方向)值开始lastVal,并且"_id"字段不能包含记录的值lastSeen.
生成的下一页是:
{ "_id": 3, "s": 3 },
{ "_id": 4, "s": 2 },
Run Code Online (Sandbox Code Playgroud)
但是现在,如果你遵循的逻辑lastVal当然是2和lastSeen现在只有单一的数组元素[4].由于下一个查询只需要从2较小或相等的值开始,因此不需要保留其他先前看到的"_id"值,因为它们不在该选择范围内.
接下来的过程如下:
var lastVal = 2,
lastSeen = [2];
db.collection.find({
"_id": { "$nin": lastSeen },
"s": { "$lte": lastVal }
}).sort({ "s": -1, "_id": 1}).limit(2).forEach(function(doc) {
if ( doc.s != lastVal ) { // Change when different
lastVal = doc.s;
lastSeen = [];
}
lastSeen.push(doc._id); // Push _id onto array
// do other things like output
})
Run Code Online (Sandbox Code Playgroud)
因此,通过遵循这种逻辑模式,您可以"存储"从结果的"previousc页面"中找到的信息,并非常有效地"向前"通过结果.
但是如果你需要跳转到"第20页"或类似的操作类型,那么你就会被困在.limit()和.skip().它的速度较慢,但这取决于你可以忍受的东西.
| 归档时间: |
|
| 查看次数: |
2661 次 |
| 最近记录: |