乐闻世界logo
搜索文章和话题

How to paginate with mongoose in node js

5 个月前提问
3 个月前修改
浏览次数51

6个答案

1
2
3
4
5
6

在使用Mongoose进行分页搜索时,通常会涉及到两个关键概念:limitskip。这两个参数可以在MongoDB的查询中使用,以实现分页的效果。limit 用于限制查询结果的数量,而 skip 用于跳过指定数量的文档。

以下是如何使用Mongoose进行分页的步骤:

  1. 确定每页的大小(即limit): 这是你想要每页显示的记录数。
  2. 计算跳过的文档数(即skip): 这是根据当前的页码计算出需要跳过的记录数。例如,如果你每页显示10条记录,那么在第二页你需要跳过的记录数为 10 * (当前页码 - 1)

示例代码

这是一个简单的例子,展示了如何使用Mongoose来实现分页搜索:

javascript
const mongoose = require('mongoose'); const { Schema } = mongoose; // 假设我们有一个用户模型 const UserSchema = new Schema({ name: String, age: Number, // 更多字段... }); const User = mongoose.model('User', UserSchema); // 分页函数 async function findUsersWithPagination(page, limit) { try { // 计算需要跳过的文档数 const skip = (page - 1) * limit; // 获取分页的数据 const users = await User.find() .skip(skip) // 跳过前面的文档 .limit(limit) // 限制返回的文档数 .exec(); // 执行查询 // 获取总的文档数以计算总页数 const count = await User.countDocuments(); return { total: count, // 总文档数 perPage: limit, // 每页文档数 currentPage: page, // 当前页码 totalPages: Math.ceil(count / limit), // 总页数 data: users // 当前页的数据 }; } catch (error) { throw error; } } // 使用分页函数,比如获取第2页的数据,每页5条记录 findUsersWithPagination(2, 5).then(paginatedResults => { console.log(paginatedResults); }).catch(err => { console.error(err); });

在这个示例中,findUsersWithPagination 函数接收 pagelimit 作为参数,然后使用这些参数来调整查询。它先计算需要跳过的记录数,然后应用 skiplimit 方法到查询中。最后,它还计算出总的文档数,以便可以返回有关分页的详细信息。

请注意,在实际的应用程序中,你可能还需要考虑排序问题,以确保文档以一致的顺序返回,这通常可以通过在 find 查询中使用 .sort() 方法来实现。

此外,如果你正在处理大量的数据,频繁地使用 skip 可能会导致性能问题,因为 skip 会导致数据库遍历过多的文档。在这种情况下,你可能需要考虑使用游标或者其他分页策略。

2024年6月29日 12:07 回复

I'm am very disappointed by the accepted answers in this question. This will not scale. If you read the fine print on cursor.skip( ):

The cursor.skip() method is often expensive because it requires the server to walk from the beginning of the collection or index to get the offset or skip position before beginning to return result. As offset (e.g. pageNumber above) increases, cursor.skip() will become slower and more CPU intensive. With larger collections, cursor.skip() may become IO bound.

To achieve pagination in a scaleable way combine a limit( ) along with at least one filter criterion, a createdOn date suits many purposes.

shell
MyModel.find( { createdOn: { $lte: request.createdOnBefore } } ) .limit( 10 ) .sort( '-createdOn' )
2024年6月29日 12:07 回复

After taking a closer look at the Mongoose API with the information provided by Rodolphe, I figured out this solution:

shell
MyModel.find(query, fields, { skip: 10, limit: 5 }, function(err, results) { ... });
2024年6月29日 12:07 回复

Pagination using mongoose, express and jade - Here's a link to my blog with more detail

shell
var perPage = 10 , page = Math.max(0, req.params.page) Event.find() .select('name') .limit(perPage) .skip(perPage * page) .sort({ name: 'asc' }) .exec(function(err, events) { Event.count().exec(function(err, count) { res.render('events', { events: events, page: page, pages: count / perPage }) }) })
2024年6月29日 12:07 回复

You can chain just like that:

shell
var query = Model.find().sort('mykey', 1).skip(2).limit(5)

Execute the query using exec

shell
query.exec(callback);
2024年6月29日 12:07 回复

In this case, you can add the query page and/ or limit to your URL as a query string.

For example:
?page=0&limit=25 // this would be added onto your URL: http:localhost:5000?page=0&limit=25

Since it would be a String we need to convert it to a Number for our calculations. Let's do it using the parseInt method and let's also provide some default values.

shell
const pageOptions = { page: parseInt(req.query.page, 10) || 0, limit: parseInt(req.query.limit, 10) || 10 } sexyModel.find() .skip(pageOptions.page * pageOptions.limit) .limit(pageOptions.limit) .exec(function (err, doc) { if(err) { res.status(500).json(err); return; }; res.status(200).json(doc); });

BTW Pagination starts with 0

2024年6月29日 12:07 回复

你的答案