it-swarm.com.de

Wie kann man mit Mongoose in Node.js paginieren?

Ich schreibe eine Webapp mit Node.js und Mungo. Wie kann ich die Ergebnisse paginieren, die ich von einem Aufruf von .find() bekomme? Ich möchte eine Funktionalität, die mit "LIMIT 50,100" in SQL vergleichbar ist.

182
Thomas

Nachdem ich mir die Mongoose API mit den von Rodolphe bereitgestellten Informationen genauer angesehen hatte, fand ich diese Lösung:

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

Ich bin sehr enttäuscht von den akzeptierten Antworten auf diese Frage. Dies wird nicht skaliert. Wenn Sie das Kleingedruckte auf der Datei "cache.skip ()" lesen

Die Cursor.skip () -Methode ist häufig teuer, da der Server vom Anfang der Sammlung oder des Indexes ablaufen muss, um den Versatz oder die Überspringposition zu ermitteln, bevor das Ergebnis zurückgegeben wird. Wenn der Versatz (z. B. Seitennummer oben) zunimmt, wird Cursor.skip () langsamer und CPU-intensiver. Bei größeren Sammlungen kann der Cursor.skip () IO gebunden werden.

Um die Paginierung auf skalierbare Weise zu erreichen, kombinieren Sie ein limit () mit mindestens einem Filterkriterium. Ein erstelltes Datum eignet sich für viele Zwecke. 

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

Pagination mit Mungo, Express und 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
            })
        })
    })
74
Madhusudhan

Sie können einfach so ketten:

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

Führen Sie die Abfrage mit exec aus.

query.exec(callback);
50
Rodolphe

Besser spät als nie.

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

In diesem Fall können Sie die Abfrage page und/oder limit zu Ihrer http-URL hinzufügen. Stichprobe ?page=0&limit=25

ÜBRIGENS Die Paginierung beginnt mit 0

31
CENT1PEDE

Sie können ein kleines Paket namens Mongoose Paginate verwenden, das es einfacher macht.

$ npm install mongoose-paginate

Fügen Sie anschließend in Ihren Routen oder in Ihrem Controller Folgendes hinzu:

/**
 * 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);
  }
}
31
Clément Renaud

Dies ist ein Beispiel, das Sie ausprobieren können.

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

Versuchen Sie es mit der Mungo-Funktion für die Paginierung. Limit ist die Anzahl der Datensätze pro Seite und Anzahl der Seite.

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

Dies ist, was ich mit dem Code gemacht habe

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

So habe ich es gemacht.

8
Indra Santosa

Hier ist eine Version, die ich an alle meine Modelle anhebe. Dies hängt von der Unterstreichung ab, um die Leistung zu verbessern und asynchron. Die Optionen ermöglichen die Auswahl und Sortierung von Feldern mit der Moose-Syntax.

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

Binden Sie es an Ihr Modellschema an.

MySchema.statics.findPaginated = findPaginated;
5
kberg

Der einfachste und schnellere Weg ist, mit der objectId .__ zu paginieren. Beispiel;

Anfangslastzustand

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

Nimm die erste und letzte ObjectId aus den Antwortdaten

Nächste Bedingung

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

Nächste Bedingung

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

In Mungo

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

Der beste Ansatz (IMO) ist die Verwendung von überspringen und begrenzen, ABER in begrenzten Sammlungen oder Dokumenten. 

Um die Abfrage in eingeschränkten Dokumenten durchzuführen, können wir einen bestimmten Index wie den Index für ein Feld vom Typ DATE verwenden. Siehe das unten

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('<fields>')
    .skip( start )
    .limit( size )        
    .exec(callback)
2
Nazmul Hassan

Dies ist eine Beispielfunktion, um das Ergebnis eines Fertigkeitenmodells mit Seitenumbruch- und Begrenzungsoptionen zu erhalten

 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

}

2
Venkatesh Somu

Das einfachste Plugin für die Paginierung.

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

Fügen Sie ein Plugin zu einem Schema hinzu und verwenden Sie dann die Modellpaginate-Methode:

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
2
Arv Ot

Einfache und leistungsstarke Paginierungslösung

async getNextDocs(last_doc_id?: string) {
    let docs

    if (!last_doc_id) {
        // get first 5 docs
        docs = await MySchema.find().sort({ _id: -1 }).limit(5)
    }
    else {
        // get next 5 docs according to that last document id
        docs = await MySchema.find({ _id: { $lt: last_doc_id} }).sort({ _id: -1 }).limit(5)
    }
    return docs
}
  1. Wenn Sie der Methode nicht die letzte Dokument-ID angeben, erhalten Sie 5 neueste Dokumente
  2. Wenn Sie die letzte Dokument-ID angegeben haben, erhalten Sie die nächsten 5 Dokumente.
1
WasiF

Obige Antwort ist gut. 

Nur ein Add-On für alle, die eher auf async-await als auf .__ stehen. versprechen !!

const findAllFoo = async (req, resp, next) => {
    const pageSize = 10;
    const currentPage = 1;

    try {
        const foos = await FooModel.find() // find all documents
            .skip(pageSize * (currentPage - 1)) // we will not retrieve all records, but will skip first 'n' records
            .limit(pageSize); // will limit/restrict the number of records to display

        const numberOfFoos = await FooModel.countDocuments(); // count the number of records for that model

        resp.setHeader('max-records', numberOfFoos);
        resp.status(200).json(foos);

    } catch (err) {
        resp.status(500).json({
            message: err
        });
    }
};

Sie können Abfrage wie folgt schreiben. 

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: Seitennummer, die vom Client als Anforderungsparameter kommt.
per_page: Keine der Ergebnisse pro Seite 

Wenn Sie den MEAN-Stapel verwenden, enthält der folgende Blogbeitrag einen Großteil der Informationen zum Erstellen einer Paginierung im Front-End mithilfe von Estrick-UI-Bootstrap und der Verwendung von Moose-Sipping- und Limit-Methoden im Back-End.

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

0
Manoj Sanjeewa
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});
            }
        });
});
0
jvitoroc

sie können auch die folgende Codezeile verwenden

per_page = parseInt(req.query.per_page) || 10
page_no = parseInt(req.query.page_no) || 1
var pagination = {
  limit: per_page ,
  skip:per_page * (page_no - 1)
}
users = await User.find({<CONDITION>}).limit(pagination.limit).skip(pagination.skip).exec()

dieser Code funktioniert in der neuesten Version von Mongo

0
Apoorv

Wenn Sie Mungo als Quelle für eine erholsame API verwenden, werfen Sie einen Blick auf ' restify-mongoose ' und ihre Abfragen. Es hat genau diese Funktionalität eingebaut. 

Jede Abfrage in einer Auflistung enthält hier hilfreiche Header 

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

Im Grunde erhalten Sie einen generischen Server mit relativ linearer Ladezeit für Abfragen an Sammlungen. Das ist großartig und etwas zu betrachten, wenn Sie in eine eigene Implementierung einsteigen möchten. 

Erzielte auch Ergebnisse mit async/waitit.

Codebeispiel unten mit einem asynchronen Handler mit hapi v17 und mongoose v5

{
            method: 'GET',
            path: '/api/v1/paintings',
            config: {
                description: 'Get all the paintings',
                tags: ['api', 'v1', 'all paintings']
            },
            handler: async (request, reply) => {
                /*
                 * Grab the querystring parameters
                 * page and limit to handle our pagination
                */
                var pageOptions = {
                    page: parseInt(request.query.page) - 1 || 0, 
                    limit: parseInt(request.query.limit) || 10
                }
                /*
                 * Apply our sort and limit
                */
               try {
                    return await Painting.find()
                        .sort({dateCreated: 1, dateModified: -1})
                        .skip(pageOptions.page * pageOptions.limit)
                        .limit(pageOptions.limit)
                        .exec();
               } catch(err) {
                   return err;
               }

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

    });
}
0
chetan

Sie können entweder überspringen () und limit () verwenden, aber das ist sehr ineffizient. Eine bessere Lösung wäre eine Sortierung nach indizierten Feldern plus Limit (). Wir bei Wunderflats haben hier eine kleine Bibliothek veröffentlicht: https://github.com/wunderflats/goosepage

0
Jan Hase