Comment paginer avec Mongoose dans Node.js?

J’écris une webapp avec Node.js et mongoose. Comment puis-je paginer les résultats d’un appel à .find() ? Je voudrais une fonctionnalité comparable à "LIMIT 50,100" en SQL.

Je suis très déçu par les réponses acceptées à cette question. Cela ne va pas évoluer. Si vous lisez les petits caractères sur cursor.skip ():

La méthode cursor.skip () est souvent coûteuse car elle oblige le serveur à se déplacer depuis le début de la collection ou de l’index pour obtenir la position de décalage ou de saut avant de commencer à renvoyer le résultat. Au fur et à mesure que l’offset (par exemple pageNumber ci-dessus) augmente, cursor.skip () deviendra plus lent et plus gourmand en CPU. Avec des collections plus importantes, cursor.skip () peut devenir lié à IO.

Pour réaliser la pagination de manière évolutive, combinez une limite () avec au moins un critère de filtre, une date de créationConvient à plusieurs fins.

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

Après avoir examiné de plus près l’API Mongoose avec les informations fournies par Rodolphe, j’ai trouvé cette solution:

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

Pagination en utilisant la mongoose, express et 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 }) }) }) 

Vous pouvez enchaîner comme ça:

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

Exécuter la requête à l’aide de exec

 query.exec(callback); 

Vous pouvez utiliser un petit paquet appelé Mongoose Paginate pour le rendre plus facile.

 $ npm install mongoose-paginate 

Après vos itinéraires ou votre contrôleur, ajoutez simplement:

 /** * 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); } } 

Mieux vaut tard que jamais.

 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); }) 

Dans ce cas, vous pouvez append la page requête et / ou la limit à votre URL http. Sample ?page=0&limit=25

BTW La pagination commence par 0

Ceci est un exemple d’exemple que vous pouvez essayer,

 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 }); }); }); 

C’est ce que j’ai fait sur le code

 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 }); 

C’est comme ça que je l’ai fait.

Essayez d’utiliser la fonction de mongoose pour la pagination. La limite est le nombre d’enregistrements par page et le numéro de la page.

 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){ }); 

Voici une version que j’attache à tous mes modèles. Cela dépend du soulignement pour plus de commodité et de l’async pour la performance. Les options permettent de sélectionner et de sortinger les champs en utilisant la syntaxe 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; } 

Attachez-le à votre schéma de modèle.

 MySchema.statics.findPaginated = findPaginated; 

La manière la plus simple et la plus rapide est de paginer avec l’object objectId;

Condition de charge initiale

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

Prenez le premier et le dernier ObjectId des données de réponse

Condition suivante

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

Condition suivante

 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); }); 

La meilleure approche (IMO) consiste à utiliser skip and limit MAIS dans des collections ou des documents limités.

Pour rendre la requête dans des documents limités, nous pouvons utiliser un index spécifique comme index sur un champ de type DATE. Voir ci-dessous

 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); }); }); } 

Plugin le plus simple pour la pagination.

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

Ajoutez un plug-in à un schéma, puis utilisez la méthode paginer modèle:

 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 

Vous pouvez écrire une requête comme celle-ci.

 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); } }); 

page: numéro de page provenant du client en tant que parameters de demande.
per_page: pas de résultats affichés par page

Si vous utilisez la stack MEAN à la suite de l’article du blog, vous obtiendrez une grande partie des informations permettant de créer une pagination en frontal en utilisant un bootstrap à interface angular et en utilisant des méthodes de saut et de limitation similaires dans le backend.

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

Vous pouvez soit utiliser skip () et limit (), mais c’est très inefficace. Une meilleure solution serait un sorting sur le champ indexé plus la limite (). Chez Wunderflats, nous avons publié une petite librairie ici: https://github.com/wunderflats/goosepage Elle utilise le premier moyen.

Si vous utilisez la mongoose comme source pour un api reposant, jetez un coup d’œil à « restify-mongoose » et à ses requêtes. Il a exactement cette fonctionnalité intégrée.

Toute requête sur une collection fournit des en-têtes utiles ici

 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 

Donc, fondamentalement, vous obtenez un serveur générique avec un temps de chargement relativement linéaire pour les requêtes aux collections. C’est génial et quelque chose à regarder si vous voulez vous lancer dans une propre implémentation.

 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}); } }); });