为了账号安全,请及时绑定邮箱和手机立即绑定

在MongoDB中实现分页

在MongoDB中实现分页

萧十郎 2019-07-13 16:01:02
我知道这是个不好的做法skip为了实现分页,因为当您的数据变得很大时skip开始消耗大量内存。克服这一麻烦的一种方法是利用自然秩序_id字段://Page 1db.users.find().limit(pageSize);//Find the id of the last document in this pagelast_id = ... //Page 2users = db.users.find({'_id'> last_id}). limit(10);问题是-我对芒果不熟悉,不知道怎样才能做到这一点last_id
查看完整描述

1 回答

?
天涯尽头无女友

TA贡献1831条经验 获得超9个赞

您正在讨论的概念可以称为“前向分页”。一个很好的理由是不像使用.skip().limit()修饰符不能用于“返回”到前一页,也不能“跳过”到特定页。至少在存储“已见”或“已发现”页面方面没有付出很大的努力,所以如果这种类型的“链接到页”分页是您想要的,那么最好还是坚持使用.skip().limit()方法,尽管存在性能缺陷。

如果只有“向前”才是可行的选择,那么以下是基本概念:

db.junk.find().limit(3){ "_id" : ObjectId("54c03f0c2f63310180151877"), "a" : 1, "b" : 1 }{ "_id" :
 ObjectId("54c03f0c2f63310180151878"), "a" : 4, "b" : 4 }{ "_id" : ObjectId("54c03f0c2f63310180151879"), "a" : 10, "b" : 10 }

当然,这是你的第一页,限制为3项。现在考虑一下,在代码迭代游标时:

var lastSeen = null;var cursor = db.junk.find().limit(3);while (cursor.hasNext()) {
   var doc = cursor.next();
   printjson(doc);
   if (!cursor.hasNext())
     lastSeen = doc._id;}

以便迭代游标并执行某些操作,并且当到达游标中的最后一项时,则存储lastSeen对现在的价值_id:

ObjectId("54c03f0c2f63310180151879")

在随后的迭代中,您只需提供_id值,该值(在会话中或其他方面)保存在查询中:

var cursor = db.junk.find({ "_id": { "$gt": lastSeen } }).limit(3);while (cursor.hasNext()) {
   var doc = cursor.next();
   printjson(doc);
   if (!cursor.hasNext())
     lastSeen = doc._id;}{ "_id" : ObjectId("54c03f0c2f6331018015187a"), "a" : 1, "b" : 1 }{ "_id" :
     ObjectId("54c03f0c2f6331018015187b"), "a" : 6, "b" : 6 }{ "_id" : ObjectId("54c03f0c2f6331018015187c"), "a" : 7, "b" : 7 }

这个过程一遍又一遍地重复,直到找不到更多的结果。

这是自然秩序的基本过程,如_id..对于其他的事情,它会变得更复杂一些。考虑以下几点:

{ "_id": 4, "rank": 3 }{ "_id": 8, "rank": 3 }{ "_id": 1, "rank": 3 }    { "_id": 3, "rank": 2 }

要将其分成两页,按排名排序,那么您需要知道的是,您已经“看到”了什么,并排除了这些结果。所以看第一页:

var lastSeen = null;var seenIds = [];var cursor = db.junk.find().sort({ "rank": -1 }).limit(2);while (cursor.hasNext()) {
   var doc = cursor.next();
   printjson(doc);
   if ( lastSeen != null && doc.rank != lastSeen )
       seenIds = [];
   seenIds.push(doc._id);
   if (!cursor.hasNext() || lastSeen == null)
     lastSeen = doc.rank;}{ "_id": 4, "rank": 3 }{ "_id": 8, "rank": 3 }

在下一次迭代中,您希望小于或等于lastSeen的“排名”分数,但也不包括那些已经看到的文档。你用$nin操作员:

var cursor = db.junk.find(
    { "_id": { "$nin": seenIds }, "rank": "$lte": lastSeen }).sort({ "rank": -1 }).limit(2);while (cursor.hasNext()) {
   var doc = cursor.next();
   printjson(doc);
   if ( lastSeen != null && doc.rank != lastSeen )
       seenIds = [];
   seenIds.push(doc._id);
   if (!cursor.hasNext() || lastSeen == null)
     lastSeen = doc.rank;}{ "_id": 1, "rank": 3 }    { "_id": 3, "rank": 2 }

实际持有多少个“seenIds”取决于您的结果有多“粒度”,该值可能会发生变化。在这种情况下,您可以检查当前的“排名”分数是否等于lastSeen价值与抛弃seenIds满足,所以它不会增长到很多。

这是“前向分页”的基本概念,供您练习和学习。


查看完整回答
反对 回复 2019-07-13
  • 1 回答
  • 0 关注
  • 819 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信