├── .gitignore ├── README.md ├── app ├── config │ └── db.config.js ├── controllers │ └── tutorial.controller.js ├── models │ ├── index.js │ └── tutorial.model.js └── routes │ └── turorial.routes.js ├── package.json └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Server side Pagination in Node.js with MongoDB and Mongoose 2 | 3 | For more detail, please visit: 4 | > [Server side Pagination in Node.js with MongoDB and Mongoose](https://bezkoder.com/node-js-mongodb-pagination/) 5 | 6 | Front-end that works well with this Back-end: 7 | > [React Pagination with API using Material-UI](https://bezkoder.com/react-pagination-material-ui/) 8 | 9 | > [React Table Pagination with react-table 7](https://bezkoder.com/react-table-pagination-server-side/) 10 | 11 | > [Angular 8 Pagination example | ngx-pagination](https://bezkoder.com/ngx-pagination-angular-8/) 12 | 13 | > [Angular 10 Pagination example | ngx-pagination](https://bezkoder.com/angular-10-pagination-ngx/) 14 | 15 | > [Angular 11 Pagination example | ngx-pagination](https://bezkoder.com/angular-11-pagination-ngx/) 16 | 17 | > [Angular 12 Pagination example | ngx-pagination](https://bezkoder.com/angular-12-pagination-ngx/) 18 | 19 | > [Vue Pagination with Axios and API example](https://bezkoder.com/vue-pagination-axios/) 20 | 21 | > [Vuetify Pagination (Server side) example](https://bezkoder.com/vuetify-pagination-server-side/) 22 | 23 | More Practice: 24 | > [Node.js, Express & MongoDb: Build a CRUD Rest Api example](https://bezkoder.com/node-express-mongodb-crud-rest-api/) 25 | 26 | > [Node.js & MongoDB: JWT Authentication & Authorization example](https://bezkoder.com/node-js-mongodb-auth-jwt/) 27 | 28 | Associations: 29 | > [MongoDB One-to-One relationship tutorial with Mongoose examples](https://bezkoder.com/mongoose-one-to-one-relationship-example/) 30 | 31 | > [MongoDB One-to-Many Relationship tutorial with Mongoose examples](https://bezkoder.com/mongoose-one-to-many-relationship/) 32 | 33 | > [MongoDB Many-to-Many Relationship with Mongoose examples](https://bezkoder.com/mongodb-many-to-many-mongoose/) 34 | 35 | Fullstack: 36 | > [Vue.js + Node.js + Express + MongoDB example](https://bezkoder.com/vue-node-express-mongodb-mevn-crud/) 37 | 38 | > [Angular 8 + Node.js + Express + MongoDB example](https://bezkoder.com/angular-mongodb-node-express/) 39 | 40 | > [Angular 10 + Node.js + Express + MongoDB example](https://bezkoder.com/angular-10-mongodb-node-express/) 41 | 42 | > [Angular 11 + Node.js + Express + MongoDB example](https://bezkoder.com/angular-11-mongodb-node-js-express/) 43 | 44 | > [Angular 12 + Node.js + Express + MongoDB example](https://bezkoder.com/angular-12-mongodb-node-js-express/) 45 | 46 | > [React + Node.js + Express + MongoDB example](https://bezkoder.com/react-node-express-mongodb-mern-stack/) 47 | 48 | Integration (run back-end & front-end on same server/port) 49 | > [Integrate React with Node.js Restful Services](https://bezkoder.com/integrate-react-express-same-server-port/) 50 | 51 | > [Integrate Angular with Node.js Restful Services](https://bezkoder.com/integrate-angular-10-node-js/) 52 | 53 | > [Integrate Vue with Node.js Restful Services](https://bezkoder.com/serve-vue-app-express/) 54 | 55 | ## Project setup 56 | ``` 57 | npm install 58 | ``` 59 | 60 | ### Run 61 | ``` 62 | node server.js 63 | ``` 64 | -------------------------------------------------------------------------------- /app/config/db.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | url: "mongodb://localhost:27017/bezkoder_db" 3 | }; 4 | -------------------------------------------------------------------------------- /app/controllers/tutorial.controller.js: -------------------------------------------------------------------------------- 1 | const db = require("../models"); 2 | const Tutorial = db.tutorials; 3 | 4 | const getPagination = (page, size) => { 5 | const limit = size ? +size : 3; 6 | const offset = page ? page * limit : 0; 7 | 8 | return { limit, offset }; 9 | }; 10 | 11 | // Create and Save a new Tutorial 12 | exports.create = (req, res) => { 13 | // Validate request 14 | if (!req.body.title) { 15 | res.status(400).send({ message: "Content can not be empty!" }); 16 | return; 17 | } 18 | 19 | // Create a Tutorial 20 | const tutorial = new Tutorial({ 21 | title: req.body.title, 22 | description: req.body.description, 23 | published: req.body.published ? req.body.published : false, 24 | }); 25 | 26 | // Save Tutorial in the database 27 | tutorial 28 | .save(tutorial) 29 | .then((data) => { 30 | res.send(data); 31 | }) 32 | .catch((err) => { 33 | res.status(500).send({ 34 | message: 35 | err.message || "Some error occurred while creating the Tutorial.", 36 | }); 37 | }); 38 | }; 39 | 40 | // Retrieve all Tutorials from the database. 41 | exports.findAll = (req, res) => { 42 | const { page, size, title } = req.query; 43 | var condition = title 44 | ? { title: { $regex: new RegExp(title), $options: "i" } } 45 | : {}; 46 | 47 | const { limit, offset } = getPagination(page, size); 48 | 49 | Tutorial.paginate(condition, { offset, limit }) 50 | .then((data) => { 51 | res.send({ 52 | totalItems: data.totalDocs, 53 | tutorials: data.docs, 54 | totalPages: data.totalPages, 55 | currentPage: data.page - 1, 56 | }); 57 | }) 58 | .catch((err) => { 59 | res.status(500).send({ 60 | message: 61 | err.message || "Some error occurred while retrieving tutorials.", 62 | }); 63 | }); 64 | }; 65 | 66 | // Find a single Tutorial with an id 67 | exports.findOne = (req, res) => { 68 | const id = req.params.id; 69 | 70 | Tutorial.findById(id) 71 | .then((data) => { 72 | if (!data) 73 | res.status(404).send({ message: "Not found Tutorial with id " + id }); 74 | else res.send(data); 75 | }) 76 | .catch((err) => { 77 | res 78 | .status(500) 79 | .send({ message: "Error retrieving Tutorial with id=" + id }); 80 | }); 81 | }; 82 | 83 | // Update a Tutorial by the id in the request 84 | exports.update = (req, res) => { 85 | if (!req.body) { 86 | return res.status(400).send({ 87 | message: "Data to update can not be empty!", 88 | }); 89 | } 90 | 91 | const id = req.params.id; 92 | 93 | Tutorial.findByIdAndUpdate(id, req.body, { useFindAndModify: false }) 94 | .then((data) => { 95 | if (!data) { 96 | res.status(404).send({ 97 | message: `Cannot update Tutorial with id=${id}. Maybe Tutorial was not found!`, 98 | }); 99 | } else res.send({ message: "Tutorial was updated successfully." }); 100 | }) 101 | .catch((err) => { 102 | res.status(500).send({ 103 | message: "Error updating Tutorial with id=" + id, 104 | }); 105 | }); 106 | }; 107 | 108 | // Delete a Tutorial with the specified id in the request 109 | exports.delete = (req, res) => { 110 | const id = req.params.id; 111 | 112 | Tutorial.findByIdAndRemove(id, { useFindAndModify: false }) 113 | .then((data) => { 114 | if (!data) { 115 | res.status(404).send({ 116 | message: `Cannot delete Tutorial with id=${id}. Maybe Tutorial was not found!`, 117 | }); 118 | } else { 119 | res.send({ 120 | message: "Tutorial was deleted successfully!", 121 | }); 122 | } 123 | }) 124 | .catch((err) => { 125 | res.status(500).send({ 126 | message: "Could not delete Tutorial with id=" + id, 127 | }); 128 | }); 129 | }; 130 | 131 | // Delete all Tutorials from the database. 132 | exports.deleteAll = (req, res) => { 133 | Tutorial.deleteMany({}) 134 | .then((data) => { 135 | res.send({ 136 | message: `${data.deletedCount} Tutorials were deleted successfully!`, 137 | }); 138 | }) 139 | .catch((err) => { 140 | res.status(500).send({ 141 | message: 142 | err.message || "Some error occurred while removing all tutorials.", 143 | }); 144 | }); 145 | }; 146 | 147 | // Find all published Tutorials 148 | exports.findAllPublished = (req, res) => { 149 | const { page, size } = req.query; 150 | const { limit, offset } = getPagination(page, size); 151 | 152 | Tutorial.paginate({ published: true }, { offset, limit }) 153 | .then((data) => { 154 | res.send({ 155 | totalItems: data.totalDocs, 156 | tutorials: data.docs, 157 | totalPages: data.totalPages, 158 | currentPage: data.page - 1, 159 | }); 160 | }) 161 | .catch((err) => { 162 | res.status(500).send({ 163 | message: 164 | err.message || "Some error occurred while retrieving tutorials.", 165 | }); 166 | }); 167 | }; 168 | -------------------------------------------------------------------------------- /app/models/index.js: -------------------------------------------------------------------------------- 1 | const dbConfig = require("../config/db.config.js"); 2 | 3 | const mongoose = require("mongoose"); 4 | const mongoosePaginate = require('mongoose-paginate-v2'); 5 | 6 | mongoose.Promise = global.Promise; 7 | 8 | const db = {}; 9 | db.mongoose = mongoose; 10 | db.url = dbConfig.url; 11 | db.tutorials = require("./tutorial.model.js")(mongoose, mongoosePaginate); 12 | 13 | module.exports = db; 14 | -------------------------------------------------------------------------------- /app/models/tutorial.model.js: -------------------------------------------------------------------------------- 1 | module.exports = (mongoose, mongoosePaginate) => { 2 | var schema = mongoose.Schema( 3 | { 4 | title: String, 5 | description: String, 6 | published: Boolean 7 | }, 8 | { timestamps: true } 9 | ); 10 | 11 | schema.method("toJSON", function() { 12 | const { __v, _id, ...object } = this.toObject(); 13 | object.id = _id; 14 | return object; 15 | }); 16 | 17 | schema.plugin(mongoosePaginate); 18 | 19 | const Tutorial = mongoose.model("tutorial", schema); 20 | return Tutorial; 21 | }; 22 | -------------------------------------------------------------------------------- /app/routes/turorial.routes.js: -------------------------------------------------------------------------------- 1 | module.exports = app => { 2 | const tutorials = require("../controllers/tutorial.controller.js"); 3 | 4 | var router = require("express").Router(); 5 | 6 | // Create a new Tutorial 7 | router.post("/", tutorials.create); 8 | 9 | // Retrieve all Tutorials 10 | router.get("/", tutorials.findAll); 11 | 12 | // Retrieve all published Tutorials 13 | router.get("/published", tutorials.findAllPublished); 14 | 15 | // Retrieve a single Tutorial with id 16 | router.get("/:id", tutorials.findOne); 17 | 18 | // Update a Tutorial with id 19 | router.put("/:id", tutorials.update); 20 | 21 | // Delete a Tutorial with id 22 | router.delete("/:id", tutorials.delete); 23 | 24 | // Create a new Tutorial 25 | router.delete("/", tutorials.deleteAll); 26 | 27 | app.use("/api/tutorials", router); 28 | }; 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-js-mongodb-pagination", 3 | "version": "1.0.0", 4 | "description": "Server side pagination in Node.js with MongoDB and Mongoose", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "nodejs", 11 | "express", 12 | "mongodb", 13 | "rest", 14 | "api", 15 | "pagination", 16 | "mongoose", 17 | "paginate", 18 | "server", 19 | "side" 20 | ], 21 | "author": "bezkoder", 22 | "license": "ISC", 23 | "dependencies": { 24 | "body-parser": "^1.19.0", 25 | "cors": "^2.8.5", 26 | "express": "^4.17.1", 27 | "mongoose": "^5.10.0", 28 | "mongoose-paginate-v2": "^1.3.9" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const bodyParser = require("body-parser"); 3 | const cors = require("cors"); 4 | 5 | const app = express(); 6 | 7 | var corsOptions = { 8 | origin: "http://localhost:8081" 9 | }; 10 | 11 | app.use(cors(corsOptions)); 12 | 13 | // parse requests of content-type - application/json 14 | app.use(bodyParser.json()); 15 | 16 | // parse requests of content-type - application/x-www-form-urlencoded 17 | app.use(bodyParser.urlencoded({ extended: true })); 18 | 19 | const db = require("./app/models"); 20 | db.mongoose 21 | .connect(db.url, { 22 | useNewUrlParser: true, 23 | useUnifiedTopology: true 24 | }) 25 | .then(() => { 26 | console.log("Connected to the database!"); 27 | }) 28 | .catch(err => { 29 | console.log("Cannot connect to the database!", err); 30 | process.exit(); 31 | }); 32 | 33 | // simple route 34 | app.get("/", (req, res) => { 35 | res.json({ message: "Welcome to bezkoder application." }); 36 | }); 37 | 38 | require("./app/routes/turorial.routes")(app); 39 | 40 | // set port, listen for requests 41 | const PORT = process.env.PORT || 8080; 42 | app.listen(PORT, () => { 43 | console.log(`Server is running on port ${PORT}.`); 44 | }); 45 | --------------------------------------------------------------------------------