个人博客
整理mongodb文档:分页
个人博客,求关注,如果文章不够清晰,麻烦指出。
文章概叙
本文主要讲下在聚合以及crud的find方法中如何使用limit还有skip进行排序。
分页的情况很经常出现,这也是这篇博客诞生的理由。
数据准备
为了方便后续的测试,这次需要准备的数据有点多,大概是一百万条。
百万级的数量能反应出skip的性能问题(毕竟用到db,必须得注意性能问题)
db.test.insertMany(new Array(1000000).fill(1).map((value, index) => ({ number: index })))
首先介绍下两位主角,一个是limit,一个是skip。
如果你需要在MongoDB中读取指定数量的数据记录,可以使用MongoDB的Limit方法,limit()方法接受一个数字参数,该参数指定从MongoDB中读取的记录条数。
我们除了可以使用limit()方法来读取指定数量的数据外,还可以使用skip()方法来跳过指定数量的数据,skip方法同样接受一个数字参数作为跳过的记录条数。
当您链接skip()和limit()时,方法链接顺序不会影响结果。服务器始终在应用限制要返回的文件数量
简单来说,我们在mysql之类的关系型数据库中使用的pagesize、pageno这些参数现在不适合了。
mongodb的分页查询,是需要两个参数,一个是跳过多少条,一个是需要查询多少条,下面举一个简单的例子:
假设我们要查询第6页的10条数据,我们需要设置我们的skip为(6-1)*10=50,设置我们的limit为10,也就是说前50条的数据被我们跳过了。
有了初步的理解,再分别介绍下如何在聚合以及find方法中使用分页。
find方法中的分页
由于在find方法中,是没有limit以及skip参数的,所以我们会直接在代码中使用skip方法以及limit方法。
db.test.find().limit(1).skip(10)
按照上面的讲述,我们查询了第11条开始的共计1条数据。
至此,你已经学会了如何在find方法中使用分页了,但请不要忽略文档中的一句话。
The skip() method requires the server to scan from the beginning of
the input results set before beginning to return results. As the
offset increases, skip() will become slower.
大体的翻译是:随着查询数据的不断增多,skip查询越后面的数据,返回越慢。
为了验证,我们需要搬出来我们的explain方法来查看更多的详情。
我们可以根据代表在该查询条件下返回文档数的"nReturned"来验证上面的说法。
首先,我们查询第11条数据,并使用explain查看查询的详情。
db.test.find().limit(1).skip(10).explain("executionStats")
接着,再查询最后一条数据。
db.test.find().limit(1).skip(999999).explain("executionStats")
而且在查询第1000000条数据的时候,也可以感觉到明显的卡顿。
根据nReturned的不同,我们就明白了当skip的值越大的时候,我们查询出来的文档数也就越多,会导致 性能下降,会出现查询缓慢的情况。
聚合通道的分页
聚合通道的分页,由于直接提供了"$limt"以及"$skip",使得我们不需要在后面拼接skip方法以及limit方法,使用的方法如下:
db.test.aggregate([{ "$limit": 3 },{ "$skip": 1 }])
上述的代码中,我们单看代码的理解是:查询从第2条开始的3条数据,也就是number分别为1,2,3的三条数据。
那么让我们打印看看查询出来的结果。
很是出乎意料,只返回了两条数据,并且返回的number还是数据库中的第二条以及第三条,说明了skip以及limit是有执行顺序的,先执行了limit的,拿出了前三条数据,再跳过这三条数据的第1条,只留下最后的两条数据。
既然如此,我们使用aggregate对skip做操作的时候,就需要考虑到执行顺序问题了。
注意点
1.上述在聚合通道的实验中,可以看到我们的顺序影响了分页的效果,所以使用分页的时候,需要注意分页所放的位置。
2.在find方法中,skip的作用是直接先将数据整理完毕,然后再查询出来,可以预测当我们要查询的数据特别后的时候,会导致我们的查询变得很慢,这也是因为一条一条数据的查询过滤。所以使用skip的时候,需要注意数据量大了就会导致性能急剧下降的问题,我们就可以尽可能的缩小查询的范围,适当的使用索引。