Tute 13: CRUDMEN: crud using express, mongoose - ariffira/node-basic GitHub Wiki
**Requirements: **
- Understand mongoose basic
- Model, Schema, collection, document etc.
- JS object, how to create new object for the model and how to create new mongoose collection
Basic Skeleton of the apps using express generator Generator link
npm install express-generator -g
//globally install express generator for you
Step 01: create your app using handlebarjs view engine
express --view=hbs crudMEN
then npm install
and gitignore file add
Step 02: Update package.json
"main": "app.js",
"scripts": {
"start": "node app.js",
"server": "nodemon app.js"
},
........
"devDependencies": {
"nodemon": "*"
}
then npm install
add this line to your app.js app.listen(5000);
Now browse http://localhost:5000/
Step 03: Open routes/index.js file and route as below:
res.render('index', { title: 'Home Page' });
add below code in index.hbs file
<h1>{{title}}</h1>
<p>My CRUDMEN TODO APP</p>
<form>
What to do? <input type="text" name="todo">
<button type="submit"> + TODO</button>
</form>
<p id="todoList"></p>
We will first add todo task by this input and see the result from terminal and later we will see it using ajax call.
Now connect mongoDB like below to app.js
npm install mongoose
// add mongoose package
const mongoose = require('mongoose');
// connect mongoose using localhost
mongoose.connect('mongodb://localhost/crudmen');
or
/* if use mlab
then use below code with iser and password
*/
mongoose.connect('mongodb://userName:[email protected]:13443/crudmen');
change index.hbs form action and method.
<form action="/todos/addTodo" method="post">
add body-parser to app.js
// body parser for form
const bodyParser = require("body-parser");
// using body parser middleware
app.use(bodyParser.urlencoded({ extended: true }));
add todo route in app.js:
const todosRouter = require('./routes/todos');
then use this route as:
app.use('/todos', todosRouter);
Now we can use this route as localhost:5000/todos/addTodo
Lets create our model and schema first:
// add mongoose package
const mongoose = require('mongoose');
// add mongoose Schema object
const Schema = mongoose.Schema;
//create a new Schema for todo
const todoSchema = new Schema({
todo: String,
createdAt: Date
});
// make new todo Schema as a model for use
// model(function name for model, schema data)
const Todo = mongoose.model('Todo', todoSchema);
// make it usable to the application
module.exports = Todo;
//shortcut of above 2 line
// const Todo = module.exports = mongoose.model('Todo', todoSchema);
C- Create and save data to DB
add route in todos.js
const express = require('express');
const router = express.Router();
const Todo = require('../models/todo');
// ADD todo
router.post('/addTodo', (req, res)=> {
// create a new todo object as like your todo schema
let newTodo = new Todo({
todo: req.body.todo,
createdAt: Date.now()
});
// create new user and save data to DB
newTodo.save(err => {
if(err) throw err;
console.log('A new Todo Saved to Database!');
res.redirect('/');
});
});
module.exports = router;
Now your todo can create and save in DB. perfect.
R-Read list of Todos from DB
add below code in todos.js route
Find() query:
/* GET todo list using find*/
router.get('/list', function(req, res, next) {
const query = Todo.find();
query.exec(function (err, result) {
if(err) throw err;
console.log(result);
res.render('todos', { todos: result });
});
});
then create todos.hbs and the add this code to check the list:
<h1>List of Todos</h1>
<ul>
{{#each todos}}
<li>
Todo number {{@index}} : {{todo}}
</li>
{{/each}}
</ul>
Now lets make it this way we can have links for all todo and onclick you will see detail view of todo task.
change your todos.hbs view
{{#each todos}}
<li>
Todo number {{@index}} : <a href="/todos/detail/{{_id}}"> {{todo}} </a>
</li>
FindOne/FindById query:
then create route inside todos.js for the detail of any todo link:
/* GET specific todo using findOne*/
router.get('/detail/:id', function(req, res, next) {
let todoId = req.params.id;
const query = Todo.findOne({ _id: todoId});
query.exec(function (err, result) {
if(err) throw err;
console.log(result);
res.render('todoDetail', { todo: result });
});
});
create a file for detail view of todo as todoDetail.hbs
<h1>Detail of This Todo</h1>
<a href="/"> Home||</a>
<a href="/todos/list"> Todos</a>
<br><hr>
<table>
<thead>
<tr>
<th>ID</th>
<th>Todo</th>
<th>Created</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{todo._id}}</td>
<td>{{todo.todo}}</td>
<td>{{todo.createdAt}}</td>
</tr>
</tbody>
</table>
Sort() aggregation for order:
Change your code in todos.js in /list route:
const query = Todo.find().sort({'createdAt': -1});
//minus is for descending order, plus is ascending
Limit() your returning list value:
add limit(5) with the same code above from todos.js /list:
const query = Todo.find().sort({'createdAt': -1}).limit(5);
U- Update todo by id from DB
first change the todos.hbs like below:
<h1>List of Todos</h1>
<a href="/"> Home</a>
<br><hr>
<ul>
{{#each todos}}
<li>
Todo number {{@index}} : {{todo}} <a href="/todos/detail/{{_id}}">Detail||</a>
<a href="/todos/update/{{_id}}">Update||</a>
<a href="/todos/delete/{{_id}}">Delete||</a>
</li>
{{/each}}
</ul>
lets create Update route in todos.js
/* Update specific todo using findById*/
router.post('/update', function(req, res, next) {
let todoId = req.body.id;
const query = Todo.findById({ _id: todoId});
query.exec(function (err, result) {
if(err) throw err;
// change old value with new
result.todo = req.body.todo;
result.createdAt = Date.now();
// save updated results
result.save(err => {
if(err) throw err;
console.log('Todo Updated....!');
res.redirect('/todos/list');
});
});
});
and also the view for update form
<h1>Update of This Todo</h1>
<a href="/"> Home||</a>
<a href="/todos/list"> Todos</a>
<br><hr>
<form action="/todos/update" method="post">
<input type="hidden" name="id" value="{{todo._id}}">
Todo: <input type="text" name="todo" value="{{todo.todo}}"><br>
<button type="submit"> Update</button>
</form>
D- Delete todo onclick delete button or link
create delete route using findByIdAndRemove():
/* Delete todo using findByIdAndRemove */
router.get('/delete/:id', function (req, res) {
let todoId = req.params.id;
const query = Todo.findByIdAndRemove({ _id: todoId});
query.exec(function (err) {
if(err) throw err;
console.log(todoId +'Todo Has been Deleted.....')
res.redirect('/todos/list');
});
});
So, We have a full functioning simple TODO app with CRUD!