MongoDB分页的Java实现和分页需求的思考

传统关系数据库中都提供了基于row number的分页功能,切换MongoDB后,想要实现分页,则需要修改一下思路。

传统分页思路

假设一页大小为10条。则

//page 1 1-10 //page 2 11-20 //page 3 21-30 ... //page n 10*(n-1) +1 - 10*n

MongoDB提供了skip()和limit()方法。

skip: 跳过指定数量的数据. 可以用来跳过当前页之前的数据,即跳过pageSize*(n-1)。
limit: 指定从MongoDB中读取的记录条数,可以当做页面大小pageSize。

所以,分页可以这样做:

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

问题

看起来,分页已经实现了,但是官方文档并不推荐,说会扫描全部文档,然后再返回结果。

The cursor.skip() method requires the server to scan from the beginning of the input results set before beginning to return results. As the offset increases, cursor.skip() will become slower.

所以,需要一种更快的方式。其实和mysql数量大之后不推荐用limit m,n一样,解决方案是先查出当前页的第一条,然后顺序数pageSize条。MongoDB官方也是这样推荐的。

正确的分页办法

我们假设基于_id的条件进行查询比较。事实上,这个比较的基准字段可以是任何你想要的有序的字段,比如时间戳。

//Page 1 db.users.find().limit(pageSize); //Find the id of the last document in this page last_id = ... //Page 2 users = db.users.find({ '_id' :{ "$gt" :ObjectId("5b16c194666cd10add402c87")} }).limit(10) //Update the last id with the id of the last document in this page last_id = ...

显然,第一页和后面的不同。对于构建分页API, 我们可以要求用户必须传递pageSize, lastId。

pageSize 页面大小

lastId 上一页的最后一条记录的id,如果不传,则将强制为第一页

降序

_id降序,第一页是最大的,下一页的id比上一页的最后的id还小。

function printStudents(startValue, nPerPage) { let endValue = null; db.students.find( { _id: { $lt: startValue } } ) .sort( { _id: -1 } ) .limit( nPerPage ) .forEach( student => { print( student.name ); endValue = student._id; } ); return endValue; }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxfjs.html