I'm currently learning mongoose and I have been making a pagination system. I made two codes, but I wonder which one of them is best way to do what I want in terms of performance and everything
Script 1:
app.get("/:page",(req,res)=>{
post.find({}).then((data)=>{
let per_page = 2; // set how many posts per page
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});
}
});
});
Script 2:
app.get("/:page",(req,res)=>{
post.count({}, (err, len)=>{
let per_page = 2; // set how many posts per page
let num_page = Number(req.params.page);
let max_pages = Math.ceil(len/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;
let promise = post.find({}).limit(per_page).skip(starting);
promise.then((data)=>{
res.render('posts', {posts:data, pages: max_pages, current_page: num_page});
});
}
});
});
Related
This is a really unusual code i haven't written myself, each day a database is updated with around 200 records.
This means we have to do 200 api calls to figure out infomation about theese records every day at 7 am.
This has been working fine until now,
the api has implemented a limit of 50 api calls pr hour, and IF you try to do 51 calls, you get banned for 24 hours...
SO, how do i make the for loop do a maximum of 50 loops here?
for (let record of records ) {
//This loop has to be limited to 50 iterations pr run.
let brregRawData = await fetch(`some url/${record.name}/someurl`);
let brregJson = await brregRawData.json()
let personNavn = brregJson.rollegrupper[0].roller[0].person.navn.fornavn
let personEtternavn = brregJson.rollegrupper[0].roller[0].person.navn.etternavn
// if mellomnavn = undefined, then do nothing
if (brregJson.rollegrupper[0].roller[0].person.navn.mellomnavn == undefined) {
var personMellomNavn = ""
} else {
let personMellomNavn = brregJson.rollegrupper[0].roller[0].person.navn.mellomnavn + " "
}
I tried looking up different ways to use a for loop, but all the solutions i looked at broke the "${record.name}" part of the url, i have to loop through an entire view of an entire database.
I'm not sure if this is right for the case, but can you define a counter outside of the loop, increment internally and break when it reaches 50.
let count = 0;
for (....)
...
if (count++ > 50) break;
...
If I'm understanding you correctly, you need to limit the number of api calls to 50 but the current implementation uses a for ... of loop. The simplest way to achieve what you're looking for with the least amount of modification is to use a standard for loop.
Assuming this all happens inside an async function...
async function limitToFiftyApiCalls(records) {
const max = Math.min(records.length, 50);
for (let i = 0; i < max; i++) {
const record = records[i];
let brregRawData = await fetch(`some url/${record.name}/someurl`);
let brregJson = await brregRawData.json();
let personNavn = brregJson.rollegrupper[0].roller[0].person.navn.fornavn;
let personEtternavn = brregJson.rollegrupper[0].roller[0].person.navn.etternavn;
// if mellomnavn = undefined, then do nothing
if (brregJson.rollegrupper[0].roller[0].person.navn.mellomnavn == undefined) {
var personMellomNavn = "";
} else {
let personMellomNavn = brregJson.rollegrupper[0].roller[0].person.navn.mellomnavn + " ";
}
}
}
The code above doesn't modify your existing code much other than limiting the number of API calls. However there's a few things you could do that would generally make the code easier to read and edit.
async function limitToFiftyApiCalls(records) {
const max = Math.min(records.length, 50);
for (let i = 0; i < max; i++) {
const record = records[i];
let personMellomNavn = "";
let brregRawData = await fetch(`some url/${record.name}/someurl`);
let brregJson = await brregRawData.json();
// why write this more than once?
// save it to a variable and make life easier
let someVar = brregJson.rollegrupper[0].roller[0].person.navn;
let personNavn = someVar.fornavn;
let personEtternavn = someVar.etternavn;
if (someVar.mellomnavn) {
personMellomNavn = someVar.mellomnavn + ' '
}
}
}
A very simple way to do this is implementing a count that increments every time the loop executes the body. So for the the loop you provided it would look like this:
let count = 0; // initialize count as 0
for (let record of records ) {
if(count >= 50) break; // break out of loop if count is equal to or greater than 50 (since count starts from 0)
//This loop has to be limited to 50 iterations pr run.
let brregRawData = await fetch(`some_url/${record.name}/some_url`);
let brregJson = await brregRawData.json()
let personNavn = brregJson.rollegrupper[0].roller[0].person.navn.fornavn
let personEtternavn = brregJson.rollegrupper[0].roller[0].person.navn.etternavn
// if mellomnavn = undefined, then do nothing
if (brregJson.rollegrupper[0].roller[0].person.navn.mellomnavn == undefined) {
var personMellomNavn = ""
} else {
let personMellomNavn = brregJson.rollegrupper[0].roller[0].person.navn.mellomnavn + " "
}
count++; // Increment the count after each iteration
}
Answer to you question:
for (let i=0; i<math.min(records.length, 50); i++ ) {
let record = records[i];
But what happens then with the records you have not checked? Will you wait 24h? I guess that's not what's expected, and instead will have to check 50 records every hour until you have checked them all (so 4 times for 200 records).
I'm trying to make pagination work but it's a bit complex for me so I need help. If someone has an idea how to make it, I would be thankful.
I need to show items that the user owns. One page can have maximum of 12 items displayed.
I have a pageData array, that returns the number of items for a category. Category "shirts" has 2 items.
pageData = [ {id:'pants',totalItems: 15},
{id:'shirts',totalItems: 2}, {id:'dresses',totalItems: 13}]
On first load I need to show 12 items (lets say 12 pants), on second load (click on load more button) I need to show 3 more pants, 2 shirts and 7 dresses.
Metadata for an item has to be fetched via api (this is just an example how to get id of specific item, I'm trying to put it somehow into code but don't have clear idea how):
for (let i = 0; i < pageData['pants'].totalItems; i++) {
const metadata = await api.getMetadata({
userId: 'userId',
id: i,
});
}
This is some code that I have but like I said, I don't really have an idea how to make it:
const getItems = async (pageData, currentPage) => {
const itemsPerPage = 12;
let fetchedData = [];
let total = 0;
let start = currentPage * itemsPerPage;
for (let i = 0; i < pageData.length; i++) {
const minRange = total;
const maxRange = minRange + itemsPerPage;
if (start >= minRange && start <= maxRange) {
const minId = minRange - total;
const maxId = maxRange - total;
for (let j = minId; j < maxId; j++) {
const metadata = await api.getMetadata({
userId: 'userId',
id: j,
});
fetchedData.push(metadata);
}
}
total += itemsPerPage;
}
};
I am learning how to do pagination. So I got a task to use skip and limit and then on top of that sort it. I've used REST API and query parameters to pass the things required like skip limit sort.
Now, my logic gets me to skip and limit running when I hit the GET API but sorting doesn't work. Can anyone provide a workaround and also explain why mine isn't working?
Code:
const getAliens = async (req, res) => {
try {
const skip = parseInt(req.query.skip);
const limit = parseInt(req.query.limit);
const sort = req.query.sort;
const sortOn = {};
if (sort != null) {
const key = sort.split(":")[0];
const value = sort.split(":")[1] == "asc" ? 1 : -1;
sortOn[key] === value;
}
const startIndex = (skip - 1) * limit;
const endIndex = skip * limit;
const response = await Alien.find()
.sort(sortOn)
.find()
.limit(limit)
.skip(startIndex)
.exec();
return ResponseUtils.success(res, response);
} catch (e) {
Log.error(e);
return ResponseUtils.error(res);
}
};
Having issue with database query in mongoose I am setting value but not getting correct not sure why, Also want to optimize the database query. I am using mongoose for counting how many records are there with matching query params(pagination) I have to make separate query. and finding the actual records with model.find({}) have to make separate query.
But actual problem is with pagination details I am trying to get
Example in below code if I set page = 1, page_size = 10 and my row_count is 3 then I suppose to get from 1, and to 1 but instead I am getting from 1 and to 11.
Not sure what I am doing wrong here.
const pagination = async (model, query, page_number, page_size, order, order_by, next) => {
const pageS = parseInt(page_number)
let page = +pageS || 1;
const limit = parseInt(page_size)
let per_page = +page_size || 10;
if (page < 1) {
page = 1;
}
if (per_page < 1) {
per_page = 1;
}
const startIndex = (
page - 1
) * per_page;
const endIndex = page * page_size
const key = `${order}`
const results = {}
// here reading the data count from database
const resultCount = await model.countDocuments(query).exec();
if (endIndex < resultCount) {
results.next = {
page: page + 1,
page_size: limit
}
}
if (startIndex > 0) {
results.previous = {
page: page - 1,
page_size: limit
}
}
try {
// here trying to search the query with applied pagination
const data = await model.find(query)
.limit(per_page)
.skip(startIndex)
.sort({ [key] : order_by })
.exec()
// here I am passing details but not getting exact to and from; from is working expected but not to
// Example if I set page = 1, page_size = 10 and my row_count is 3 then I suppose to get from 1, and to 1 but intead I am getting from 1 and to 11.
const pagination_details = {
data: data,
meta: {
page,
page_size: per_page,
row_count: parseInt(resultCount, 10),
page_count: Math.ceil(resultCount / per_page ),
from:startIndex + 1,
to: endIndex + 1,
order: order,
order_by: order_by
}
}
return pagination_details
next()
} catch (e) {
console.log(e);
console.error(e);
}
};
Can anyone help me here to achieve the right data, what I am making mistake here. Might be something logical mistake
You have forgotten to divide the start and end indexes by the per_page to get page numbers, try replacing:
from:startIndex + 1,
to: endIndex + 1,
with:
from: Math.floor(startIndex / per_page) + 1,
to: Math.ceil(endIndex / per_page) + 1,
I want to access shopify api using Node.js with request method. I get first 50 items but i need to send the last id of the products i get as a response so it can loop through all the products until we don't have another id (i check that if the last array is not 50 in length.)
So when i get the response of lastID i want to feed that again to the same function until the Parraylength is not 50 or not 0.
Thing is request works asynchronously and i don't know how to feed the same function with the result lastID in node.js.
Here is my code
let importedData = JSON.parse(body);
//for ( const product in importedData.products ){
// console.log(`${importedData.products[product].id}`);
//}
lastID = importedData.products[importedData.products.length-1].id;
let lastIDD = lastID;
console.log(`This is ${lastID}`);
importedData ? console.log('true') : console.log('false');
let Prarraylength = importedData.products.length;
console.log(Prarraylength);
//console.log(JSON.stringify(req.headers));
return lastIDD;
});```
You can use a for loop and await to control the flow of your script in this case.
I'd suggest using the request-native-promise module to get items, since it has a promise based interface, but you could use node-fetch or axios (or any other http client) too.
In this case, to show you the logic, I've created a mock rp which normally you'd create as follows:
const rp = require("request-promise-native");
You can see we're looping through the items, 50 at a time. We're passing the last id as a url parameter to the next rp call. Now this is obviously going to be different in reality, but I believe you can easily change the logic as you require.
const totalItems = 155;
const itemsPerCall = 50;
// Mock items array...
const items = Array.from({ length: totalItems}, (v,n) => { return { id: n+1, name: `item #${n+1}` } });
// Mock of request-promise (to show logic..)
// Replace with const rp = require("request-promise-native");
const rp = function(url) {
let itemPointer = parseInt(url.split("/").slice(-1)[0]);
return new Promise((resolve, reject) => {
setTimeout(() => {
let slice = items.slice(itemPointer, itemPointer + itemsPerCall);
itemPointer += itemsPerCall;
resolve( { products: slice });
}, 500);
})
}
async function getMultipleRequests() {
let callIndex = 0;
let lastID = 0;
const MAX_CALLS = 20;
const EXPECTED_ARRAY_LENGTH = 50;
for(let callCount = 1; callCount < MAX_CALLS; callCount++) {
// Replace with the actual url..
let url = "/products/" + lastID;
let importedData = await rp(url);
lastID = importedData.products[importedData.products.length - 1].id;
console.log("Call #: " + ++callIndex + ", Item count: " + importedData.products.length + ", lastID: " + lastID);
if (importedData.products.length < EXPECTED_ARRAY_LENGTH) {
console.log("Reached the end of products...exiting loop...");
break;
}
}
}
getMultipleRequests();