290

Node.js と mongoose を使用して webapp を作成しています。.find()呼び出しから得た結果をページ分割するにはどうすればよいですか? "LIMIT 50,100"SQLに匹敵する機能が欲しい。

4

32 に答える 32

319

この質問で受け入れられた回答に非常に失望しています。これはスケーリングしません。cursor.skip( ) の詳細を読むと、次のようになります。

cursor.skip() メソッドは、サーバーがコレクションまたはインデックスの先頭から移動してオフセットを取得するか、結果を返し始める前に位置をスキップする必要があるため、多くの場合コストがかかります。オフセット (上記の pageNumber など) が増加すると、cursor.skip() は遅くなり、CPU の負荷が高くなります。大きなコレクションでは、cursor.skip() が IO バウンドになることがあります。

スケーラブルな方法でページネーションを実現するには、 limit( ) と少なくとも 1 つのフィルター条件を組み合わせます。createdOn の日付は多くの目的に適しています。

MyModel.find( { createdOn: { $lte: request.createdOnBefore } } )
.limit( 10 )
.sort( '-createdOn' )
于 2014-05-13T19:48:13.993 に答える
270

Rodolphe から提供された情報を使用して Mongoose API を詳しく調べた後、次の解決策を見つけました。

MyModel.find(query, fields, { skip: 10, limit: 5 }, function(err, results) { ... });
于 2011-04-04T15:15:29.713 に答える
144

マングース、エクスプレス、ジェイドを使用したページネーション -詳細については、私のブログへのリンクを参照してください。

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
            })
        })
    })
于 2013-02-11T22:29:32.743 に答える
63

次のようにチェーンできます。

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

を使用してクエリを実行しますexec

query.exec(callback);
于 2011-04-04T14:40:24.267 に答える
40

これを簡単にするMongoose Paginateという小さなパッケージを使用できます。

$ npm install mongoose-paginate

ルートまたはコントローラーの後に、次を追加するだけです:

/**
 * 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);
  }
}
于 2012-10-10T05:47:10.113 に答える
17

これは、これを試すことができるサンプル例です。

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
      });
  });
 });
于 2016-02-02T08:11:01.563 に答える
10

これは私がコードでそれをしたことです

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

それが私がやった方法です。

于 2014-10-21T08:00:19.533 に答える
6

これは、すべてのモデルに取り付けるバージョンです。利便性のためにアンダースコアに依存し、パフォーマンスのために非同期に依存します。opts により、マングース構文を使用したフィールドの選択と並べ替えが可能になります。

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

モデル スキーマにアタッチします。

MySchema.statics.findPaginated = findPaginated;
于 2013-02-14T15:50:15.997 に答える
4

これを実装する確実な方法は、クエリ文字列を使用してフロントエンドから値を渡すことです。ページ #2​​ を取得し、出力を25 resultsに制限するとします。 クエリ文字列は次のようになります。
?page=2&limit=25 // this would be added onto your URL: http:localhost:5000?page=2&limit=25

コードを見てみましょう:

// We would receive the values with req.query.<<valueName>>  => e.g. req.query.page
// Since it would be a String we need to convert it to a Number in order to do our
// necessary calculations. Let's do it using the parseInt() method and let's also provide some default values:

  const page = parseInt(req.query.page, 10) || 1; // getting the 'page' value
  const limit = parseInt(req.query.limit, 10) || 25; // getting the 'limit' value
  const startIndex = (page - 1) * limit; // this is how we would calculate the start index aka the SKIP value
  const endIndex = page * limit; // this is how we would calculate the end index

// We also need the 'total' and we can get it easily using the Mongoose built-in **countDocuments** method
  const total = await <<modelName>>.countDocuments();

// skip() will return a certain number of results after a certain number of documents.
// limit() is used to specify the maximum number of results to be returned.

// Let's assume that both are set (if that's not the case, the default value will be used for)

  query = query.skip(startIndex).limit(limit);

  // Executing the query
  const results = await query;

  // Pagination result 
 // Let's now prepare an object for the frontend
  const pagination = {};

// If the endIndex is smaller than the total number of documents, we have a next page
  if (endIndex < total) {
    pagination.next = {
      page: page + 1,
      limit
    };
  }

// If the startIndex is greater than 0, we have a previous page
  if (startIndex > 0) {
    pagination.prev = {
      page: page - 1,
      limit
    };
  }

 // Implementing some final touches and making a successful response (Express.js)

const advancedResults = {
    success: true,
    count: results.length,
    pagination,
    data: results
 }
// That's it. All we have to do now is send the `results` to the frontend.
 res.status(200).json(advancedResults);

このロジックをミドルウェアに実装して、さまざまなルート/コントローラーに使用できるようにすることをお勧めします。

于 2020-01-21T20:21:58.903 に答える
2

最も簡単で迅速な方法は、objectId の例でページ付けすることです。

初期負荷条件

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

応答データから最初と最後の ObjectId を取得します

ページの次の条件

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

ページの次の条件

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

マングースでは

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);
});
于 2016-07-08T11:08:57.173 に答える
1

これは、ページネーションと制限オプションを使用してスキル モデルの結果を取得する関数の例です。

 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

}

于 2018-09-19T12:33:36.367 に答える
1
let page,limit,skip,lastPage, query;
 page = req.params.page *1 || 1;  //This is the page,fetch from the server
 limit = req.params.limit * 1 || 1; //  This is the limit ,it also fetch from the server
 skip = (page - 1) * limit;   // Number of skip document
 lastPage = page * limit;   //last index 
 counts = await userModel.countDocuments() //Number of document in the collection

query = query.skip(skip).limit(limit) //current page

const paginate = {}

//For previous page
if(skip > 0) {
   paginate.prev = {
       page: page - 1,
       limit: limit
} 
//For next page
 if(lastPage < counts) {
  paginate.next = {
     page: page + 1,
     limit: limit
}
results = await query //Here is the final results of the query.
于 2020-03-30T17:13:52.597 に答える
0

skip() と limit() のいずれかを使用できますが、非常に非効率的です。より良い解決策は、インデックス付きフィールドと limit() の並べ替えです。Wunderflats では、ここで小さなライブラリを公開しています: https://github.com/wunderflats/goosepage 最初の方法を使用します。

于 2015-12-05T19:27:21.790 に答える
0

このようにクエリを書くことができます。

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 : リクエスト パラメータとしてクライアントから送信されるページ番号。
per_page : ページごとに表示される結果の数

MEAN スタックを使用している場合、次のブログ投稿では、angular-UI ブートストラップを使用してフロントエンドでページネーションを作成し、バックエンドで mongoose のスキップおよび制限メソッドを使用するための多くの情報を提供しています。

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

于 2015-06-06T17:07:58.547 に答える
-1

async/await でも結果を出すことができました。

hapi v17 および 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;
               }

            }
        }
于 2019-01-18T14:44:31.143 に答える