Saya menulis webapp dengan Node.js dan luwak. Bagaimana saya bisa memberi nomor hasil yang saya dapatkan dari .find()
panggilan telepon? Saya ingin fungsionalitas yang sebanding dengan "LIMIT 50,100"
di SQL.
Saya menulis webapp dengan Node.js dan luwak. Bagaimana saya bisa memberi nomor hasil yang saya dapatkan dari .find()
panggilan telepon? Saya ingin fungsionalitas yang sebanding dengan "LIMIT 50,100"
di SQL.
Jawaban:
Saya sangat kecewa dengan jawaban yang diterima dalam pertanyaan ini. Ini tidak akan skala. Jika Anda membaca tulisan kecil di cursor.skip ():
Metode cursor.skip () seringkali mahal karena mengharuskan server berjalan dari awal koleksi atau indeks untuk mendapatkan posisi offset atau lompati sebelum mulai mengembalikan hasil. Saat offset (mis. PageNumber di atas) meningkat, cursor.skip () akan menjadi lebih lambat dan lebih intensif CPU. Dengan koleksi yang lebih besar, cursor.skip () dapat menjadi terikat IO.
Untuk mencapai pagination dengan cara yang dapat dikombinasi, gabungkan batas () bersama dengan setidaknya satu kriteria filter, tanggal yang dibuat sesuai dengan banyak tujuan.
MyModel.find( { createdOn: { $lte: request.createdOnBefore } } )
.limit( 10 )
.sort( '-createdOn' )
-createdOn
', Anda akan mengganti nilai request.createdOnBefore
dengan nilai paling sedikit dari createdOn
pengembalian di set hasil sebelumnya, dan kemudian meminta kembali.
Setelah melihat lebih dekat pada API Mongoose dengan informasi yang diberikan oleh Rodolphe, saya menemukan solusi ini:
MyModel.find(query, fields, { skip: 10, limit: 5 }, function(err, results) { ... });
Pagination menggunakan luwak, express, dan jade - Inilah tautan ke blog saya dengan lebih detail
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
})
})
})
Math.max(0, undefined)
akan kembali undefined
, Ini bekerja untuk saya:let limit = Math.abs(req.query.limit) || 10;
let page = (Math.abs(req.query.page) || 1) - 1;
Schema.find().limit(limit).skip(limit * page)
Anda dapat rantai seperti itu:
var query = Model.find().sort('mykey', 1).skip(2).limit(5)
Jalankan permintaan menggunakan exec
query.exec(callback);
var page = req.param('p'); var per_page = 10; if (page == null) { page = 0; } Location.count({}, function(err, count) { Location.find({}).skip(page*per_page).limit(per_page).execFind(function(err, locations) { res.render('index', { locations: locations }); }); });
Dalam hal ini, Anda dapat menambahkan kueri page
dan / atau limit
ke URL Anda sebagai string kueri.
Sebagai contoh:
?page=0&limit=25 // this would be added onto your URL: http:localhost:5000?page=0&limit=25
Karena itu akan menjadi, String
kita perlu mengubahnya menjadi Number
untuk perhitungan kita. Mari kita lakukan dengan menggunakan parseInt
metode dan mari kita juga memberikan beberapa nilai default.
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 dimulai dengan0
mongoose
.
Anda dapat menggunakan paket kecil yang disebut Mongoose Paginate yang membuatnya lebih mudah.
$ npm install mongoose-paginate
Setelah di rute atau pengontrol Anda, cukup tambahkan:
/**
* 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);
}
}
Ini adalah contoh contoh yang dapat Anda coba ini,
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
});
});
});
Coba gunakan fungsi luwak untuk pagination. Batas adalah jumlah catatan per halaman dan jumlah halaman.
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){
});
Inilah yang saya lakukan pada kode
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
});
Begitulah cara saya melakukannya.
count()
sudah ditinggalkan. gunakancountDocuments()
Pertanyaan;
search = productName,
Params;
halaman = 1
// Pagination
router.get("/search/:page", (req, res, next) => {
const resultsPerPage = 5;
const page = req.params.page >= 1 ? req.params.page : 1;
const query = req.query.search;
Product.find({ name: query })
.select("name")
.sort({ name: "asc" })
.limit(resultsPerPage)
.skip(resultsPerPage * page)
.then((results) => {
return res.status(200).send(results);
})
.catch((err) => {
return res.status(500).send(err);
});
});
Ini adalah versi yang saya lampirkan ke semua model saya. Itu tergantung pada garis bawah untuk kenyamanan dan async untuk kinerja. Pilihan memungkinkan untuk pemilihan bidang dan penyortiran menggunakan sintaks luwak.
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;
}
Lampirkan ke skema model Anda.
MySchema.statics.findPaginated = findPaginated;
Solusi pagination sederhana dan kuat
async getNextDocs(no_of_docs_required: number, last_doc_id?: string) {
let docs
if (!last_doc_id) {
// get first 5 docs
docs = await MySchema.find().sort({ _id: -1 }).limit(no_of_docs_required)
}
else {
// get next 5 docs according to that last document id
docs = await MySchema.find({_id: {$lt: last_doc_id}})
.sort({ _id: -1 }).limit(no_of_docs_required)
}
return docs
}
last_doc_id
: id dokumen terakhir yang Anda dapatkan
no_of_docs_required
: jumlah dokumen yang ingin Anda ambil yaitu 5, 10, 50 dll.
last_doc_id
metode tersebut, Anda akan mendapatkan 5 dokumen terbarulast_doc_id
maka Anda akan mendapatkan 5 dokumen berikutnya yaitu.Jawaban di atas bagus.
Hanya add-on untuk siapa saja yang async-tunggu daripada janji !!
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
});
}
};
Anda dapat menggunakan baris kode berikut juga
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()
kode ini akan berfungsi dalam versi mongo terbaru
Pendekatan yang solid untuk mengimplementasikan ini adalah untuk melewatkan nilai-nilai dari frontend menggunakan string kueri . Katakanlah kita ingin mendapatkan halaman # 2 dan juga membatasi output hingga 25 hasil .
String kueri akan terlihat seperti ini:?page=2&limit=25 // this would be added onto your URL: http:localhost:5000?page=2&limit=25
Mari kita lihat kodenya:
// 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);
Saya akan menyarankan mengimplementasikan logika ini ke middleware sehingga Anda dapat menggunakannya untuk berbagai rute / pengontrol.
Cara termudah dan lebih cepat adalah, paginasi dengan objectId Contoh;
Kondisi muatan awal
condition = {limit:12, type:""};
Ambil ObjectId pertama dan terakhir dari data respons
Halaman kondisi selanjutnya
condition = {limit:12, type:"next", firstId:"57762a4c875adce3c38c662d", lastId:"57762a4c875adce3c38c6615"};
Halaman kondisi selanjutnya
condition = {limit:12, type:"next", firstId:"57762a4c875adce3c38c6645", lastId:"57762a4c875adce3c38c6675"};
Pada luwak
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);
});
Pendekatan terbaik (IMO) adalah menggunakan lewati dan batasi BUT dalam koleksi atau dokumen terbatas.
Untuk membuat kueri dalam dokumen terbatas, kita bisa menggunakan indeks seperti indeks tertentu pada bidang tipe DATE. Lihat itu di bawah
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)
Plugin paling mudah untuk pagination.
https://www.npmjs.com/package/mongoose-paginate-v2
Tambahkan plugin ke skema dan kemudian gunakan metode model paginate:
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
Ini adalah contoh fungsi untuk mendapatkan hasil model keterampilan dengan opsi pagination dan limit
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
}
Anda dapat menulis kueri seperti ini.
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);
}
});
halaman: nomor halaman yang berasal dari klien sebagai parameter permintaan.
per_page: tidak ada hasil yang ditampilkan per halaman
Jika Anda menggunakan tumpukan MEAN setelah posting blog menyediakan banyak informasi untuk membuat pagination di ujung depan menggunakan bootstrap sudut-UI dan menggunakan metode lompat jauh dan batas luak di backend.
lihat: https://techpituwa.wordpress.com/2015/06/06/mean-js-pagination-with-angular-ui-bootstrap/
Anda dapat menggunakan skip () dan limit (), tetapi sangat tidak efisien. Solusi yang lebih baik akan menjadi semacam bidang diindeks plus batas (). Kami di Wunderflats telah menerbitkan lib kecil di sini: https://github.com/wunderflats/goosepage Ini menggunakan cara pertama.
Jika Anda menggunakan luwak sebagai sumber api yang nyenyak, lihat ' restify-luwak' ' dan pertanyaannya. Ini persis memiliki fungsi ini bawaan.
Setiap kueri pada koleksi memberikan tajuk yang bermanfaat di sini
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
Jadi pada dasarnya Anda mendapatkan server generik dengan waktu buka yang relatif linier untuk kueri ke koleksi. Itu luar biasa dan sesuatu untuk dilihat jika Anda ingin pergi ke implementasi sendiri.
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});
}
});
});
**//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);
});
});
}
Gunakan plugin sederhana ini.
https://github.com/WebGangster/mongoose-paginate-v2
Instalasi
npm install mongoose-paginate-v2
const mongoose = require('mongoose');
const mongoosePaginate = require('mongoose-paginate-v2');
const mySchema = new mongoose.Schema({
/* your schema definition */
});
mySchema.plugin(mongoosePaginate);
const myModel = mongoose.model('SampleModel', mySchema);
myModel.paginate().then({}) // Usage
berdasarkan
menjawab:
//assume every page has 50 result
const results = (req.query.page * 1) * 50;
MyModel.find( { fieldNumber: { $lte: results} })
.limit( 50 )
.sort( '+fieldNumber' )
//one thing left is create a fieldNumber on the schema thas holds ducument number
Menggunakan ts-luwak-pagination
const trainers = await Trainer.paginate(
{ user: req.userId },
{
perPage: 3,
page: 1,
select: '-password, -createdAt -updatedAt -__v',
sort: { createdAt: -1 },
}
)
return res.status(200).json(trainers)
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.
Mampu mencapai hasil dengan async / menunggu juga.
Contoh kode di bawah ini menggunakan async handler dengan hapi v17 dan luoose 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;
}
}
}