¿Cómo paginar con Mongoose en Node.js?

Estoy escribiendo una aplicación web con Node.js y mongoose. ¿Cómo puedo paginar los resultados que obtengo de una llamada .find() ? Me gustaría una funcionalidad comparable a "LIMIT 50,100" en SQL.

Estoy muy decepcionado por las respuestas aceptadas en esta pregunta. Esto no va a escalar. Si lees la letra pequeña en cursor.skip ():

El método cursor.skip () suele ser costoso porque requiere que el servidor camine desde el principio de la colección o el índice para obtener la posición de desplazamiento o salto antes de comenzar a devolver el resultado. A medida que aumenta el desplazamiento (por ejemplo, pageNumber arriba), cursor.skip () se volverá más lento y más intensivo en CPU. Con colecciones más grandes, cursor.skip () puede convertirse en IO enlazado.

Para lograr la paginación de manera escalable, combine un límite () junto con al menos un criterio de filtro, una fecha de creación creada para muchos propósitos.

 MyModel.find( { createdOn: { $lte: request.createdOnBefore } } ) .limit( 10 ) .sort( '-createdOn' ) 

Después de observar más de cerca la API de Mongoose con la información proporcionada por Rodolphe, descubrí esta solución:

 MyModel.find(query, fields, { skip: 10, limit: 5 }, function(err, results) { ... }); 

Paginación usando mongoose, expreso y jade – http://madhums.me/2012/08/20/pagination-using-mongoose-express-and-jade/

 var perPage = 10 , page = Math.max(0, req.param('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 }) }) }) 

Puedes encadenar de esa manera:

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

Ejecutar la consulta usando exec

 query.exec(callback); 

Puedes usar un pequeño paquete llamado Mongoose Paginate que lo hace más fácil.

 $ npm install mongoose-paginate 

Luego en tus rutas o controlador, solo agrega:

 /** * querying for `all` {} items in `MyModel` * paginating by second page, 10 items per page (10 results, page 2) **/ MyModel.paginate({}, 2, 10, function(error, pageCount, paginatedResults) { if (error) { console.error(error); } else { console.log('Pages:', pageCount); console.log(paginatedResults); } } 

Mejor tarde que nunca.

 var pageOptions = { page: req.query.page || 0, limit: req.query.limit || 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); }) 

En este caso, puede agregar la page consulta y / o el limit a su URL de http. ?page=0&limit=25 Muestra ?page=0&limit=25

La paginación BTW comienza con 0

Este es un ejemplo de ejemplo, puede probar esto,

 var _pageNumber = 2, _pageSize = 50; Student.count({},function(err,count){ Student.find({}, null, { sort: { Name: 1 } }).skip(_pageNumber > 0 ? ((_pageNumber - 1) * _pageSize) : 0).limit(_pageSize).exec(function(err, docs) { if (err) res.json(err); else res.json({ "TotalCount": count, "_Array": docs }); }); }); 

Esto es lo que hice en codigo.

 var paginate = 20; var page = pageNumber; MySchema.find({}).sort('mykey', 1).skip((pageNumber-1)*paginate).limit(paginate) .exec(function(err, result) { // Write some stuff here }); 

Así es como lo hice.

Trate de usar la función de mongoose para la paginación. El límite es el número de registros por página y el número de la página.

 var limit = parseInt(body.limit); var skip = (parseInt(body.page)-1) * parseInt(limit); db.Rankings.find({}) .sort('-id') .limit(limit) .skip(skip) .exec(function(err,wins){ }); 

Aquí hay una versión que adjunto a todos mis modelos. Depende del guión bajo para mayor comodidad y asíncrono para el rendimiento. Las opciones permiten la selección de campos y la clasificación utilizando la syntax de mongoose.

 var _ = require('underscore'); var async = require('async'); function findPaginated(filter, opts, cb) { var defaults = {skip : 0, limit : 10}; opts = _.extend({}, defaults, opts); filter = _.extend({}, filter); var cntQry = this.find(filter); var qry = this.find(filter); if (opts.sort) { qry = qry.sort(opts.sort); } if (opts.fields) { qry = qry.select(opts.fields); } qry = qry.limit(opts.limit).skip(opts.skip); async.parallel( [ function (cb) { cntQry.count(cb); }, function (cb) { qry.exec(cb); } ], function (err, results) { if (err) return cb(err); var count = 0, ret = []; _.each(results, function (r) { if (typeof(r) == 'number') { count = r; } else if (typeof(r) != 'number') { ret = r; } }); cb(null, {totalCount : count, results : ret}); } ); return qry; } 

Adjúntelo a su esquema modelo.

 MySchema.statics.findPaginated = findPaginated; 

La forma más fácil y rápida es paginar con el Ejemplo objectId;

Condición de carga inicial

 condition = {limit:12, type:""}; 

Tome el primer y último ObjectId de los datos de respuesta

Página siguiente condición

 condition = {limit:12, type:"next", firstId:"57762a4c875adce3c38c662d", lastId:"57762a4c875adce3c38c6615"}; 

Página siguiente condición

 condition = {limit:12, type:"next", firstId:"57762a4c875adce3c38c6645", lastId:"57762a4c875adce3c38c6675"}; 

En mongoose

 var condition = {}; var sort = { _id: 1 }; if (req.body.type == "next") { condition._id = { $gt: req.body.lastId }; } else if (req.body.type == "prev") { sort = { _id: -1 }; condition._id = { $lt: req.body.firstId }; } var query = Model.find(condition, {}, { sort: sort }).limit(req.body.limit); query.exec(function(err, properties) { return res.json({ "result": result); }); 

El mejor enfoque (IMO) es usar omitir y limitar PERO dentro de colecciones o documentos limitados.

Para realizar la consulta dentro de documentos limitados, podemos usar un índice específico como índice en un campo de tipo FECHA. Mira eso abajo

 let page = ctx.request.body.page || 1 let size = ctx.request.body.size || 10 let DATE_FROM = ctx.request.body.date_from let DATE_TO = ctx.request.body.date_to var start = (parseInt(page) - 1) * parseInt(size) let result = await Model.find({ created_at: { $lte: DATE_FROM, $gte: DATE_TO } }) .sort({ _id: -1 }) .select('') .skip( start ) .limit( size ) .exec(callback) 
 **//localhost:3000/asanas/?pageNo=1&size=3** //requiring asanas model const asanas = require("../models/asanas"); const fetchAllAsanasDao = () => { return new Promise((resolve, reject) => { var pageNo = parseInt(req.query.pageNo); var size = parseInt(req.query.size); var query = {}; if (pageNo < 0 || pageNo === 0) { response = { "error": true, "message": "invalid page number, should start with 1" }; return res.json(response); } query.skip = size * (pageNo - 1); query.limit = size; asanas .find(pageNo , size , query) .then((asanasResult) => { resolve(asanasResult); }) .catch((error) => { reject(error); }); }); } 

El plugin más fácil para la paginación.

https://www.npmjs.com/package/mongoose-paginate-v2

Agregue un complemento a un esquema y luego use el método de paginación modelo:

 var mongoose = require('mongoose'); var mongoosePaginate = require('mongoose-paginate-v2'); var mySchema = new mongoose.Schema({ /* your schema definition */ }); mySchema.plugin(mongoosePaginate); var myModel = mongoose.model('SampleModel', mySchema); myModel.paginate().then({}) // Usage 

Esta es una función de ejemplo para obtener el resultado del modelo de habilidades con paginación y opciones de límite

  export function get_skills(req, res){ console.log('get_skills'); var page = req.body.page; // 1 or 2 var size = req.body.size; // 5 or 10 per page var query = {}; if(page < 0 || page === 0) { result = {'status': 401,'message':'invalid page number,should start with 1'}; return res.json(result); } query.skip = size * (page - 1) query.limit = size Skills.count({},function(err1,tot_count){ //to get the total count of skills if(err1) { res.json({ status: 401, message:'something went wrong!', err: err, }) } else { Skills.find({},{},query).sort({'name':1}).exec(function(err,skill_doc){ if(!err) { res.json({ status: 200, message:'Skills list', data: data, tot_count: tot_count, }) } else { res.json({ status: 401, message: 'something went wrong', err: err }) } }) //Skills.find end } });//Skills.count end 

}

Puede escribir consulta de esta manera.

 mySchema.find().skip((page-1)*per_page).limit(per_page).exec(function(err, articles) { if (err) { return res.status(400).send({ message: err }); } else { res.json(articles); } }); 

página: número de página que proviene del cliente como parámetros de solicitud.
per_page: no de resultados mostrados por página

Si está utilizando la stack MEAN, la siguiente publicación del blog proporciona gran parte de la información para crear una paginación en la parte delantera utilizando un progtwig de arranque de interfaz de usuario angular y utilizando los métodos de omisión y límite de mongoose en la parte posterior.

consulte: https://techpituwa.wordpress.com/2015/06/06/mean-js-pagination-with-angular-ui-bootstrap/

Puedes usar skip () y limit (), pero es muy ineficiente. Una mejor solución sería una clasificación en el campo indexado más el límite (). Nosotros en Wunderflats publicamos una pequeña librería aquí: https://github.com/wunderflats/goosepage Utiliza la primera forma.

Si está utilizando mongoose como fuente para una api tranquila, eche un vistazo a ‘ restify-mongoose ‘ y sus consultas. Tiene exactamente esta funcionalidad incorporada.

Cualquier consulta en una colección proporciona encabezados que son útiles aquí

 test-01:~$ curl -s -D - localhost:3330/data?sort=-created -o /dev/null HTTP/1.1 200 OK link: ; rel="first", ; rel="next", ; rel="last" ..... Response-Time: 37 

Básicamente, obtiene un servidor genérico con un tiempo de carga relativamente lineal para consultas a colecciones. Eso es asombroso y algo que ver si quieres entrar en una implementación propia.

 app.get("/:page",(req,res)=>{ post.find({}).then((data)=>{ let per_page = 5; let num_page = Number(req.params.page); let max_pages = Math.ceil(data.length/per_page); if(num_page == 0 || num_page > max_pages){ res.render('404'); }else{ let starting = per_page*(num_page-1) let ending = per_page+starting res.render('posts', {posts:data.slice(starting,ending), pages: max_pages, current_page: num_page}); } }); });