How to make pagination with NodeJS? - node.js

i have a controller and i want to make pagination with 5 records per page. How can i do it with Nodejs i really need help.
const getPagination = (page, size) => {
const limit = size ? +size : 5; // Fetch 5 records
const offset = page ? page * limit : 0;// Start from page 0
return { limit, offset };
};
// Find all car with condition and how can i add pagination ?
export function findAllCar( req, res){
const name = req.query.name;
const color = req.query.color;
const brand = req.query.brand;
var condition = name ? {
name: { [Op.iLike]: `%${name}%` },
color: { [Op.iLike]: `%${color}%` },
brand: { [Op.iLike]: `%${brand}%` },
} : null;
Car.findAll({ where: condition })
.then(data => {
res.send(data);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Some error occurred while retrieving CARS."
});
});
}

you need to add limit and offset inside the query.
var condition = name ? {
name: { [Op.iLike]: `%${name}%` },
color: { [Op.iLike]: `%${color}%` },
brand: { [Op.iLike]: `%${brand}%` },
} : null;
const paginate = (query, { page, pageSize }) => {
const offset = page * pageSize;
const limit = pageSize;
return {
...query,
offset,
limit,
};
};
model.findAll(
paginate(
{
where: condition
},
{ page, pageSize },
),
);
Also, you can refer to this here

you can use this
model.findAll({
limit: 5,
offset: 0,
where: {}, // conditions
});

Related

Submitting without files resets the all images in the array when making a PATCH request

I'm trying to make a dynamic field for adding team members using Formik.
In my backend, if I do not choose any file and edit only other field such as "memberName" I'm getting message saying;
"Cast to embedded failed for value "{
_id: '63c5687832a80d5d8f717715',
memberName: 'qqaa',
memberJobTitle: 'qq',
memberDescription: 'qq',
images: [ 'undefined' ]
}" (type Object) at path "team" because of "CastError""
I want to keep the existing images if there is no changes in the input field. I'm having this issue for a week and couldn't figure it out.
This is my controller for making a PATCH request;
const updateSection = async (req, res, next) => {
const files = req.files;
const {
pageId,
welcomeTitle,
welcomeDescription,
aboutUsTitle,
aboutUsDescription,
team,
teamTitle,
} = req.body;
let updates = {};
//update other fields if they are provided in the request body
if (welcomeTitle) {
updates.welcomeTitle = welcomeTitle;
}
if (welcomeDescription) {
updates.welcomeDescription = welcomeDescription;
}
if (aboutUsTitle) {
updates.aboutUsTitle = aboutUsTitle;
}
if (aboutUsDescription) {
updates.aboutUsDescription = aboutUsDescription;
}
if (teamTitle) {
updates.teamTitle = teamTitle;
}
if (team) {
let teamPromises = []; //create an empty array to store promises for updating or creating team members
// updates.team.images = [];
team.forEach((item, i) => {
// item -> current team member being processed, i-> index in the array
let teamMember = {
_id: item._id,
memberName: item.memberName,
memberJobTitle: item.memberJobTitle,
memberDescription: item.memberDescription,
images: item.images,
};
if (files && files[i]) {
let file = files[i];
let img = fs.readFileSync(file.path);
let decode_image = img.toString("base64");
teamMember.images = [
{
filename: file.originalname,
contentType: file.mimetype,
imageBase64: decode_image,
},
];
} else {
teamMember.images = item.images;
}
teamPromises.push(
Section.updateOne(
{ pageId: pageId, "team._id": item._id },
{ $set: { "team.$": teamMember } },
{ new: false }
)
);
});
Promise.all(teamPromises)
.then((result) => {
res.status(200).json({ message: "Section updated successfully!" });
})
.catch((error) => {
res.status(500).json({ error: error.message });
});
} else {
//update other fields if no team member provided
Section.findOneAndUpdate({ pageId: pageId }, updates).then(() => {
res.status(200).json({ message: "Section updated successfully!" });
});
}
};

How to rotate individual pages in a pdf in web viewer

I am using web viewer and want to rotate individual pages and update them in the database.
Right now I am able to rotate the whole pdf only.
I am following this doc https://www.pdftron.com/documentation/web/guides/manipulation/rotate/
but not able to understand much
export default function PdfTron(props: any): ReactElement {
const viewer = useRef<HTMLDivElement>(null);
const {DrawingLibDetailsState, DrawingLibDetailsDispatch}: any = useContext(DrawingLibDetailsContext);
const [newInstance, setNewInstance] = useState<any>(null);
const [currentPage, setCurrentPage] = useState<any>(null);
const {dispatch, state }:any = useContext(stateContext);
//console.log("currentPage in state",currentPage)
useEffect(() => {
WebViewer(
{
path: '/webviewer/lib',
licenseKey: process.env["REACT_APP_PDFTRON_LICENSE_KEY"],
initialDoc: '',
filename: 'drawings',
extension: "pdf",
isReadOnly: true,
fullAPI: true,
disabledElements: [
// 'leftPanelButton',
// // 'selectToolButton',
// 'stickyToolButton',
// 'toggleNotesButton',
]
},
viewer.current as HTMLDivElement,
).then((instance: any) => {
setNewInstance(instance)
// you can now call WebViewer APIs here...
});
}, []);
useEffect(() => {
if(DrawingLibDetailsState?.parsedFileUrl?.url && newInstance ){
const s3Key = DrawingLibDetailsState?.parsedFileUrl?.s3Key;
const pageNum = s3Key.split('/')[s3Key.split('/').length-1].split('.')[0];
const fileName = DrawingLibDetailsState?.drawingLibDetails[0]?.fileName?.replace(".pdf", "");
const downloadingFileName = `page${pageNum}_${fileName}`;
newInstance.loadDocument(DrawingLibDetailsState?.parsedFileUrl?.url, {extension: "pdf",
filename: downloadingFileName ? downloadingFileName : 'drawing',})
const { documentViewer } = newInstance.Core;
const pageRotation = newInstance.Core.PageRotation;
const clickDocument =newInstance.Core.DocumentViewer.Click;
const pageNumber = newInstance.Core.pageNum;
//get page rotation from the PDF
documentViewer.addEventListener('rotationUpdated', (rotation: number) => {
updateRotation(rotation)
})
// trigger an event after the document loaded
documentViewer.addEventListener('documentLoaded', async() => {
const doc = documentViewer.getDocument();
const rotation = DrawingLibDetailsState?.drawingLibDetails[0]?.sheetsReviewed?.pdfRotation ?
DrawingLibDetailsState?.drawingLibDetails[0]?.sheetsReviewed?.pdfRotation : 0
documentViewer.setRotation(rotation)
})
documentViewer.on('pageNumberUpdated', () => {
DrawingLibDetailsDispatch(setDrawingPageNumber(0));
})
}
}, [DrawingLibDetailsState?.parsedFileUrl?.url, newInstance]);
useEffect(() => {
if(DrawingLibDetailsState?.drawingPageNum && newInstance ){
const { documentViewer, PDFNet } = newInstance.Core;
PDFNet.initialize()
documentViewer.addEventListener('documentLoaded',async () => {
await PDFNet.initialize()
const pdfDoc = documentViewer.getDocument();
const doc = await pdfDoc.getPDFDoc();
newInstance.UI.pageManipulationOverlay.add([
{
type: 'customPageOperation',
header: 'Custom options',
dataElement: 'customPageOperations',
operations: [
{
title: 'Alert me',
img: '/path-to-image',
onClick: (selectedPageNumbers:any) => {
alert(`Selected thumbnail pages: ${selectedPageNumbers}`);
},
dataElement: 'customPageOperationButton',
},
],
},
{ type: 'divider' },
]);
documentViewer.setCurrentPage(DrawingLibDetailsState?.drawingPageNum, true);
});
documentViewer.setCurrentPage(DrawingLibDetailsState?.drawingPageNum, true);
}
}, [DrawingLibDetailsState?.drawingPageNum]);
useEffect(() => {
if(props?.drawingSheetsDetails?.fileSize){
fetchSheetUrl(props?.drawingSheetsDetails)
}
}, [props?.drawingSheetsDetails]);
const fetchSheetUrl = (file: any) => {
const payload = [{
fileName: file.fileName,
key: file.sourceKey,
expiresIn: 100000000,
// processed: true
}];
getSheetUrl(payload);
}
const getSheetUrl = async (payload: any) => {
try {
dispatch(setIsLoading(true));
const fileUploadResponse = await postApi('V1/S3/downloadLink', payload);
if(fileUploadResponse.success){
const fileData = {
s3Key: payload[0].key,
url: fileUploadResponse.success[0].url
}
DrawingLibDetailsDispatch(setParsedFileUrl(fileData));
}
dispatch(setIsLoading(false));
} catch (error) {
Notification.sendNotification(error, AlertTypes.warn);
dispatch(setIsLoading(false));
}
}
const updateRotation = (rotation: number) => {
props.updateRotation(rotation)
}
return (
<>
<div className="webviewer" ref={viewer}></div>
</>
)
}
In WebViewer 8.0 you would need to enable the left panel by default when the document is loaded, and then use event delegation on left panel to watch for button clicks on the single page rotation buttons.
const { documentViewer } = instance.Core
documentViewer.addEventListener('documentLoaded',()=>{
let panelElement = instance.docViewer.getScrollViewElement().closest('#app').querySelector('[data-element="thumbnailsPanel"]');
if (!parentElement) {
instance.UI.toggleElementVisibility('leftPanel');
panelElement = instance.docViewer.getScrollViewElement().closest('#app').querySelector('[data-element="thumbnailsPanel"]');
}
panelElement.addEventListener('click', (e) => {
if (e.target.dataset?.element === 'thumbRotateClockwise' || e.target.dataset?.element === 'thumbRotateCounterClockwise') {
// The single page rotations are performed asychronously and there are no events firings in 8.0, so we have to manually add a delay before the page finishes rotating itself.
setTimeout(() => {
const pageNumber = parseInt(e.target.parentElement.previousSibling.textContent);
const rotation = instance.docViewer.getDocument().getPageRotation(pageNumber);
console.log('page ', pageNumber, ' self rotation is ', rotation);
}, 500);
}
});
})
If you have the option to upgrade to the latest WebViewer, you can listen to the ‘pagesUpdated’ event on documentViewer and the code becomes shorter & cleaner:
const { documentViewer } = instance.Core
documentViewer.addEventListener('pagesUpdated',(changes)=>{
changes.contentChanged.forEach(pageNumber=>{
const rotation = documentViewer.getDocument().getPageRotation(pageNumber)
console.log('page ', pageNumber, ' self rotation is ', rotation);
})
})
For both situations, when you load the document back, you can use documentViewer.getDocument().rotatePages to rotate to your saved rotations.
assuming we have the saved page rotations data structured like this
const rotationData = [
{pageNumber: 1, rotation: 180},
{pageNumber: 3, rotation: 90},
{pageNumber: 4, rotation: 270},
]
We can use the following code to rotate our individual pages back:
const { documentViewer } = instance.Core
documentViewer.addEventListener('documentLoaded',()=>{
rotationData.forEach(page=>{
const originalRotation = documentViewer.getDocument().getPageRotation(page.pageNumber)
if (originalRotation !== page.rotation) {
documentViewer.getDocument().rotatePages([page.pageNumber], (page.rotation-originalRotation)/90);
}
})
})

How to regex filter with boolean Mongoose Paginate V2?

I use Mongoose Paginate V2 in nodeJs, but i have a question that how to make a regex filter with Boolean type?
My Code is
exports.allData = (req, res, next) => {
const { page, size, title, show } = req.query;
var condition = {}
if(title){
condition.title = { $regex: new RegExp(title), $options: "i" }
}
if(tayang){
condition.show = { $regex: new RegExp(show), $options: "true|false" }
}
const { limit, offset } = getPagination(page, size);
var options = {
populate: [
{
path: 'user',
select: 'username'
}],
sort: ({ createdAt: -1 })
};
Article.paginate(condition, { offset, limit, options })
.then((data) => {
res.send({
totalItems: data.totalDocs,
articles: data.docs,
totalPages: data.totalPages,
currentPage: data.page - 1,
});
})
.catch((err) => {
logger.error(req.method + ": " + req.originalUrl + ", message: " + err.message)
next(createError.InternalServerError())
});
};
I want to filter data "show" field is true or false with regex. Thanks before.
You can check if the show query param is present and use the $eq operator to construct the query.
if ('show' in req.query) {
condition.show = { $eq: show === 'true' }
}

How to do sorting in nodejs in backend

This is my node Api
router.post("/*****", async function(req, res, err) {
let limit = 5;
let offset = 0;
tblAdmin
.findAndCountAll()
.then(data => {
console.log("hello world", req.body);
let page = (req.body.page && req.body.page) || 1;
let sortfield = req.body.sortfield;
let sortOrder = req.body.sortOrder;
let pages = Math.ceil(data.count / limit);
offset = limit * (page - 1);
tblAdmin
.findAll({
attributes: ["id", "firstName", "lastName", "status", "email"],
limit: limit,
offset: offset
// order: [`firstName`, `DESC`]
// $sort: { id: 1 }
})
.then(users => {
res.status(200).json({
status: 1,
message: "Data has been retrieved",
result: users,
count: data.count,
pages: pages
});
});
// res.status(200).json({
// status: 1,
// message: "Data has been retrieved",
// data: data.map(result => {
// return {
// id: result.id,
// firstName: result.firstName,
// lastName: result.lastName,
// status: result.status,
// email: result.email
// };
// })
// });
})
.catch(err => {
res.status(500).json({
status: 0,
message: "Data is not retrieved from database"
});
});
});
and this is my react front end
axios.post(`http://abc/**`, params).then(res => {
const pagination = { ...this.state.pagination };
let apiData = res.data.result;
console.log("Data", apiData);
console.log("params", params);
if (res.data.status === 1) {
const objects = apiData.map(row => ({
key: row.id,
id: row.id,
firstName: row.firstName,
lastName: row.lastName,
status: row.status,
email: row.email
}));
console.log(res.data);
pagination.total = res.data.count;
this.setState({
loading: false,
data: objects,
pagination
});
} else {
console.log("Database status is not 1!");
}
});
now this is shown on a table and when i select the field of table in front end it should show ascending or descending order i need to do that order in backend.
from front end i m sending param which includes pagination, sortfield and sortorder and i m getting that in backend now what should i do to change the table according to my order?
The document can be found here
router.post("/*****", async function(req, res, err) {
let limit = 5;
let offset = 0;
tblAdmin
.findAndCountAll()
.then(data => {
console.log("hello world", req.body);
let page = (req.body.page && req.body.page) || 1;
let sortfield = req.body.sortfield;
let sortOrder = req.body.sortOrder;
let pages = Math.ceil(data.count / limit);
offset = limit * (page - 1);
tblAdmin
.findAll({
attributes: ["id", "firstName", "lastName", "status", "email"],
limit: limit,
offset: offset
order: [[sortfield || 'id', sortOrder || 'DESC']] // fixed at here
})
.then(users => {
res.status(200).json({
status: 1,
message: "Data has been retrieved",
result: users,
count: data.count,
pages: pages
});
});
})
.catch(err => {
res.status(500).json({
status: 0,
message: "Data is not retrieved from database"
});
});
});
Edit 1: Add sort default if sortfield or sortOrder is undefined

Sequelize pagination

Using sequelize on my nodejs web app, I want to query posts using pagination (by date). Reading sequelize docs, they offer to use offset and limit.
Since I want to display the posts from new to old, I need to consider the date they were created. For example, if I limit the first query to 10 page, and before executing the second query a new post was created, the next query with offset of 10 will result a duplicate post from the last query.
How should I implement the pagination so it will support new entries?
The easiest way to do this is to use Sequelize's findAndCountAll
Post.findAndCountAll({
where: {...},
order: [...],
limit: 5,
offset: 0,
}).then(function (result) {
res.render(...);
});
Here, result has both the result of your query and count as result.rows and result.count. You can then increment the offset and use this for pagination.
Sequelize documentation for findAndCountAll
Try this:
const paginate = (query, { page, pageSize }) => {
const offset = page * pageSize;
const limit = pageSize;
return {
...query,
offset,
limit,
};
};
model.findAll(
paginate(
{
where: {}, // conditions
},
{ page, pageSize },
),
);
In order to avoid boilerplate code
If you want to have a stable pagination, don't paginate on row offset, since it's volatile, for the reason you mention.
You should aim for paginating on a value that is stable over time and use a where clause for filtering results. The best case would be if you have an auto-incrementing id, but the post date could also be reasonable.
Something like:
Post.findAll({
where: { createdDate: { $lt: previousDate },
limit: 10
})
You need to keep track of previousDate for this ofc. This approach also has some caveats, and you may need to combine it with client-side de-duplication.
Here is a blog post that probably has all the answers you need:
Pagination: You're (Probably) Doing It Wrong
With findAndCountAll here count is useful for pagination, from this total count we can limit as we want and also with async and await
let resAccidents = await ModalName.findAndCountAll({ where: { createdByID: employeeID }, offset: 0, limit: 10 });
this will return a count of total records as per where condition and 1st 10 records of it, then increase the value of offset to fetch further records.
You can simply do that
let limit = 10
let offset = 0 + (req.body.page - 1) * limit
Posts.findAndCountAll({
offset: offset,
limit: limit,
order: [
['date', 'ASC']
]
}).then(async result => {
return res.status(200).json({
status: true,
message: res.__('success'),
innerData: result
})
})
.catch(err => {
return validator.InvalidResponse(res, `${err}`)
})
Try this instead:
db.findAll({
offset: page_no,// your page number
limit:25,// your limit
This one solved my issue.
export const paginate = (query, schema) => {
let page = query.page ? query.page - 1 : 0;
page = page < 0 ? 0 : page;
let limit = parseInt(query.limit || 10);
limit = limit < 0 ? 10 : limit;
const offset = page * limit;
const where = {};
delete query.page;
delete query.limit;
Object.keys(schema).forEach((key) => {
schema[key] && query[key] ? (where[key] = query[key]) : null;
});
return {
where: where,
offset,
limit,
};
};
#Get()
findAll(#Query() query): unknown {
return this.model.findAll(paginate(query, {xx:1}));
}
/model?xx=yy&page=1&limit=5
var defered = Q.defer();
const offset = queryString.offset * queryString.limit;
const limit = queryString.limit;
var queryWhere = { class_id: { $ne: null }, section_id: { $ne: null } };
var searchClass = {};
var searchSection = {};
if (queryString) {
if (queryString.class && queryString.class !== "") {
searchClass = { class_id: { $eq: queryString.class } };
} else if (queryString.class && queryString.class === "") {
searchClass = { class_id: { $ne: null } };
}
if (queryString.section && queryString.section !== "") {
searchSection = { section_id: { $eq: queryString.section } };
} else if (queryString.section && queryString.section === "") {
searchSection = { section_id: { $ne: null } };
}
}
queryWhere = {
$and: [[searchClass], [searchSection]]
};
const schoolDB = require("../../db/models/tenant")(schema);
const Student = schoolDB.model("Student");
Student.findAll({
attributes: [
"id",
"first_name",
"last_name",
"profile_image_url",
"roll_number",
"emergency_contact_number"
],
offset: offset,
limit: limit,
where: queryWhere,
order: [["roll_number", "ASC"]]
})
.then(result => {
defered.resolve(result);
})
.catch(err => {
defered.reject(err);
});
Recommended using Sequelize's own operators
var defered = Q.defer();
const offset = queryString.offset * queryString.limit;
const limit = queryString.limit;
var queryWhere = { class_id: { $ne: null }, section_id: { $ne: null } };
var searchClass = {};
var searchSection = {};
if (queryString) {
if (queryString.class && queryString.class !== "") {
searchClass = { class_id: { $eq: queryString.class } };
} else if (queryString.class && queryString.class === "") {
searchClass = { class_id: { $ne: null } };
}
if (queryString.section && queryString.section !== "") {
searchSection = { section_id: { $eq: queryString.section } };
} else if (queryString.section && queryString.section === "") {
searchSection = { section_id: { $ne: null } };
}
}
queryWhere = {
$and: [[searchClass], [searchSection]]
};
const schoolDB = require("../../db/models/tenant")(schema);
const Student = schoolDB.model("Student");
Student.findAll({
attributes: [
"id",
"first_name",
"last_name",
"profile_image_url",
"roll_number",
"emergency_contact_number"
],
offset: offset,
limit: limit,
where: queryWhere,
order: [["roll_number", "ASC"]]
})
.then(result => {
defered.resolve(result);
})
.catch(err => {
defered.reject(err);
});

Resources