mongodb 分页查询替代skip的方式

来源:互联网 发布:完美日记化妆品知乎 编辑:程序博客网 时间:2024/06/05 03:23

以典型的列表api来说:下拉刷新是获取最新信息,然后上拉加载下一页

常见api要写的2个接口

  • get_latest(model,count)
  • get_with_page(number,size)

get_latest一般是取最新的数据,比如我们常见的下拉刷新,一般都是这样的接口的。由于2次下拉之间,可能非常长的时间间隔,所以取到的数据会把当前列表的数据冲掉。

通常做法

  • 如果n(比如n=30s)分钟内有连续请求,提示最近已更新,没必要再刷,或者直接返回当前数据
  • 如果取到新数据,将当前列表的数据冲掉,保证数据一致性

如果判断我到最后一页了

常见的办法是取出总数,除以pagesize,然后判断当前页是否和总页数-1

n = all_count - 1

量少的时候,毫无感觉,如果量大了,你去查一下count(*)是啥后果呢?

所以比较好的做法是按照id去查,前端根据每次返回的数据条数,如果条数等于pagesize,你就可以取下一页数据,相反,如果取到的数据小于pagesize,你就知道没有那么多数据可以取了,即到了尾页。此时只要disable获取下一页的按钮即可。

使用 skip() 和 limit() 实现

//Page 1db.users.find().limit (10)//Page 2db.users.find().skip(10).limit(10)//Page 3db.users.find().skip(20).limit(10)........

抽象一下就是:检索第n页的代码应该是这样的

db.users.find().skip(pagesize*(n-1)).limit(pagesize)

当然,这是假定在你在2次查询之间没有任何数据插入或删除操作,你的系统能么?

当然大部分oltp系统无法确定不更新,所以skip只是个玩具,没太大用

而且skip+limit只适合小量数据,数据一多就卡死,哪怕你再怎么加索引,优化,它的缺陷都那么明显。

如果你要处理大量数据集,你需要考虑别的方案的。

使用 find() 和 limit() 实现

之前用skip()方法没办法更好的处理大规模数据,所以我们得找一个skip的替代方案。

为此我们想平衡查询,就考虑根据文档里有的时间戳或者id

在这个例子中,我们会通过‘_id’来处理(用时间戳也一样,看你设计的时候有没有类似created_at这样的字段)。

‘_id’是mongodb ObjectID类型的,ObjectID 使用12 字节的存储空间,每个字节两位十六进制数字,是一个24 位的字符串,包括timestamp, machined, processid, counter 等。下面会有一节单独讲它是怎么构成的,为啥它是唯一的。

使用_id实现分页的大致思路如下

  1. 在当前页内查出最后1条记录的_id,记为last_id
  2. 把记下来的last_id,作为查询条件,查出大于last_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);//Update the last id with the id of the last document in this pagelast_id = ...

这只是示范代码,我们来看一下在Robomongo 0.8.4客户端里如何写

db.usermodels.find({'_id' :{ "$gt" :ObjectId("55940ae59c39572851075bfd")} }).limit(20).sort({_id:-1})

根据上面接口说明,我们仍然要实现2个接口

  • get_latest(model,count)
  • get_next_page_with_last_id(last_id, size)
原创粉丝点击