MongoDB is open source, NoSQL, document oriented database designed for scaling and performance. MongoDB can be easily interface with Node.js cause Mongo provides official native driver. In this tutorial we are going to learn following things.
- Setting up MongoDB
- Installing NPM modules.
- Setting up our Server.
- Creating basic MongoDB model.
- Creating basic RESTful API’s using Node.js and MongoDB.
Seting up MongoDB
Visit official MongoDB download page to download MongoDB installer for specific operating system. They will detect your OS and offer you stable version to download. Once you have download it, just follow the setup wizard instructions to install it in your system.
To begin using the MongoDB, you need to specify the location where MongoDB will store your databases. That location will be a normal folder. Create any folder say “mongoData” at location easily accessible to you say on Desktop and open up terminal.
Open up terminal and run following command to start MongoDB Server at default port.
mongod --dbpath c:/Users/Shahid/Desktop/mongoData //for windows
mongod --dbpath /home/Shahid/Desktop/mongoData //for Linux
You should see following screen after running above command.
Now open up another terminal and run following command.
You should see following screen.
To create new database, run following command.
Inside database, you create collections which actually like a table in database that will store your information. We will do all that using code. Let’s move to next step !
Installing NPM modules.
MongoDB provide native driver for Node.js called “mongodb” which you can use to connect to MongoDB and perform various CRUD operation. There is another MongoDB recommended node module which is quite famous called “mongoose” and this one we are going to use.
Create project folder and start your project by using “npm init” cause its good practice. This wizard will ask you some question like name, version, test script etc and at the end you will have your package.json file ready.
To install mongoose run following command.
Here is my package.json.
"name": "nodeMongo",
"version": "1.0.0",
"description": "Node.js and MongoDb tutorial.",
"main": "Server.js",
"scripts": {
"test": "mocha"
},
"repository": {
"type": "git",
"url": "https://github.com/codeforgeek/Node-and-mongo-tutorial"
},
"keywords": [
"Node.js",
"mongoDb"
],
"author": "Shahid Shaikh",
"license": "ISC",
"bugs": {
"url": "https://github.com/codeforgeek/Node-and-mongo-tutorial/issues"
},
"homepage": "https://github.com/codeforgeek/Node-and-mongo-tutorial",
"dependencies": {
"body-parser": "^1.13.3",
"express": "^4.13.3",
"mongoose": "^4.1.2"
}
}
You can copy this and create your package file and run following command to install the modules.
This is it, we have bootstrapped our project. Let’s write some code.
Setting up our Server.
To set up our project Server, we are going to use Express module. Here is our basic server.
var app = express();
var bodyParser = require("body-parser");
var router = express.Router();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({"extended" : false}));
router.get("/",function(req,res){
res.json({"error" : false,"message" : "Hello World"});
});
app.use('/',router);
app.listen(3000);
console.log("Listening to PORT 3000");
Let’s run our code and see how it’s behaving. Run the code using following command.
Let’s test our first route using PostMan ( REST simulator chrome extension ).
All right. We have set up our Server successfully. Moving right along !
Creating basic MongoDB model.
Mongoose allows you to create models ( OR Schema OR tables ) in your MongoDB database. To connect mongoDB database to our Node.js here is two-line of code.
mongoose.connect('mongodb://localhost:27017/demoDb');
/*
* MongoDB port is 27017 by default.
* Assuming you have created mongoDB database named "demoDb".
*/
Unlike SQL queries, MongoDB uses JSON structure to create schema in model. So for example if you want to create simple table user_login with two column say email and password you need to write following code
var userSchema = {
"userEmail" : String,
"userPassword" : String
};
mongoose.model('user_login',userSchema);
Create separate folder called “model” and inside create file named “mongo.js” and add following line of code.
mongoose.connect('mongodb://localhost:27017/demoDb');
// create instance of Schema
var mongoSchema = mongoose.Schema;
// create schema
var userSchema = {
"userEmail" : String,
"userPassword" : String
};
// create model if not exists.
module.exports = mongoose.model('userLogin',userSchema);
In Server.js add following line.
Creating RESTful API’s using Node and MongoDB.
We have covered complete tutorial on RESTful API’s using MySQL. Let’s develop simple RESTful engine using MongoDB.
So our Resource will be “users” and on that we are going to allow following CRUD operation.
- GET /users – Return all Users from MongoDB
- POST /users – Add new user in MongoDB
- GET /users/:id – Return User with matched ID
- PUT /users/:id – Update users information
- DELETE /users/:id – Delete particular user
1 : GET /users – Return all Users from MongoDB.
Here is our code.
var app = express();
var bodyParser = require("body-parser");
var mongoOp = require("./models/mongo");
var router = express.Router();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({"extended" : false}));
router.get("/",function(req,res){
res.json({"error" : false,"message" : "Hello World"});
});
//route() will allow you to use same path for different HTTP operation.
//So if you have same URL but with different HTTP OP such as POST,GET etc
//Then use route() to remove redundant code.
router.route("/users")
.get(function(req,res){
var response = {};
mongoOp.find({},function(err,data){
// Mongo command to fetch all data from collection.
if(err) {
response = {"error" : true,"message" : "Error fetching data"};
} else {
response = {"error" : false,"message" : data};
}
res.json(response);
});
});
app.use('/',router);
app.listen(3000);
console.log("Listening to PORT 3000");
To test the API, open up POSTMAN and hit “localhost:3000/users”. You should see following screen. ( I added some users while testing )
2 : POST /users – Add new user in MongoDB.
Here is a code.
var app = express();
var bodyParser = require("body-parser");
var mongoOp = require("./models/mongo");
var router = express.Router();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({"extended" : false}));
router.get("/",function(req,res){
res.json({"error" : false,"message" : "Hello World"});
});
//route() will allow you to use same path for different HTTP operation.
//So if you have same URL but with different HTTP OP such as POST,GET etc
//Then use route() to remove redundant code.
router.route("/users")
.get(function(req,res){
------------------------------------------------------
})
.post(function(req,res){
var db = new mongoOp();
var response = {};
// fetch email and password from REST request.
// Add strict validation when you use this in Production.
db.userEmail = req.body.email;
// Hash the password using SHA1 algorithm.
db.userPassword = require('crypto')
.createHash('sha1')
.update(req.body.password)
.digest('base64');
db.save(function(err){
// save() will run insert() command of MongoDB.
// it will add new data in collection.
if(err) {
response = {"error" : true,"message" : "Error adding data"};
} else {
response = {"error" : false,"message" : "Data added"};
}
res.json(response);
});
});
app.use('/',router);
app.listen(3000);
console.log("Listening to PORT 3000");
To add new user in MongoDB, open up POSTMAN, use POST as type and add following in input payload.
"email" : "shahid@codeforgeek.com",
"password" : "simple"
}
3: GET /users/:id – Return User with matched ID.
Here is our code.
var app = express();
var bodyParser = require("body-parser");
var mongoOp = require("./models/mongo");
var router = express.Router();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({"extended" : false}));
router.get("/",function(req,res){
res.json({"error" : false,"message" : "Hello World"});
});
//route() will allow you to use same path for different HTTP operation.
//So if you have same URL but with different HTTP OP such as POST,GET etc
//Then use route() to remove redundant code.
router.route("/users")
.get(function(req,res){
------------------------------
})
.post(function(req,res){
------------------------------
});
router.route("/users/:id")
.get(function(req,res){
var response = {};
mongoOp.findById(req.params.id,function(err,data){
// This will run Mongo Query to fetch data based on ID.
if(err) {
response = {"error" : true,"message" : "Error fetching data"};
} else {
response = {"error" : false,"message" : data};
}
res.json(response);
});
})
app.use('/',router);
app.listen(3000);
console.log("Listening to PORT 3000");
To check this route, hit our first API to get all users and copy any one ID. Then just paste the ID right after the URL and hit the request.
4 : PUT /users/:id – Update users information.
Here is our code.
var app = express();
var bodyParser = require("body-parser");
var mongoOp = require("./models/mongo");
var router = express.Router();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({"extended" : false}));
router.get("/",function(req,res){
res.json({"error" : false,"message" : "Hello World"});
});
//route() will allow you to use same path for different HTTP operation.
//So if you have same URL but with different HTTP OP such as POST,GET etc
//Then use route() to remove redundant code.
router.route("/users")
.get(function(req,res){
-------------------------------
})
.post(function(req,res){
-------------------------------
});
router.route("/users/:id")
.get(function(req,res){
-------------------------------
})
.put(function(req,res){
var response = {};
// first find out record exists or not
// if it does then update the record
mongoOp.findById(req.params.id,function(err,data){
if(err) {
response = {"error" : true,"message" : "Error fetching data"};
} else {
// we got data from Mongo.
// change it accordingly.
if(req.body.userEmail !== undefined) {
// case where email needs to be updated.
data.userEmail = req.body.userEmail;
}
if(req.body.userPassword !== undefined) {
// case where password needs to be updated
data.userPassword = req.body.userPassword;
}
// save the data
data.save(function(err){
if(err) {
response = {"error" : true,"message" : "Error updating data"};
} else {
response = {"error" : false,"message" : "Data is updated for "+req.params.id};
}
res.json(response);
})
}
});
})
app.use('/',router);
app.listen(3000);
console.log("Listening to PORT 3000");
In order to execute it, first get the ID of any user and the select type of request as PUT and pass data which you want to update in JSON format.
You can select that user detail to cross verify it. Just change the type to GET.
5 : DELETE /users/:id – Delete particular user.
Here is our code.
var app = express();
var bodyParser = require("body-parser");
var mongoOp = require("./models/mongo");
var router = express.Router();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({"extended" : false}));
router.get("/",function(req,res){
res.json({"error" : false,"message" : "Hello World"});
});
router.route("/users")
.get(function(req,res){
----------------------------------------
})
.post(function(req,res){
----------------------------------------
});
router.route("/users/:id")
.get(function(req,res){
----------------------------------------
})
.put(function(req,res){
----------------------------------------
})
.delete(function(req,res){
var response = {};
// find the data
mongoOp.findById(req.params.id,function(err,data){
if(err) {
response = {"error" : true,"message" : "Error fetching data"};
} else {
// data exists, remove it.
mongoOp.remove({_id : req.params.id},function(err){
if(err) {
response = {"error" : true,"message" : "Error deleting data"};
} else {
response = {"error" : true,"message" : "Data associated with "+req.params.id+"is deleted"};
}
res.json(response);
});
}
});
})
app.use('/',router);
app.listen(3000);
console.log("Listening to PORT 3000");
Just select the request type as DELETE and pass the ID which user you want to delete.
Conclusion:
We have covered the information which you need to begin with MongoDB and Node.js along with RESTful api development tutorial. MongoDB is great in performing READ operation, so if you have a large amount of data say 1000TB then SQL is quite slow at that time. You can use big data software like MongoDB to handle that kind of record set.
Mongoose is wrapper over native Node.js driver provided by MongoDB. MongoDB official site recommends this module too.
Further reading :
- RESTful API wiki.
- MongoDB native driver documentation.
- Mongoose official site.
- RESTful API using Node and MySQL.
Thank you.
Your welcome.
What is the MonogDB Table name? Do I need to create manually??
To test the API, open up POSTMAN and hit “localhost:3000/users”. You should see following screen. ( I added some users while testing )
as a generic alternative to setting up mongoDB in your example code you could use:
mongod –dbpath C:%HOMEPATH%DesktopmongoData //for windows
mongod –dbpath ~/Desktop/mongoData //for Mac and Linux
I POST to users, but I got some errors:
TypeError: Not a string or buffer at TypeError (native) at Hash.update (crypto.js:119:16) at E:ProjectsNode-and-mongo-tutorial-masterServer.js:30:64 at Layer.handle [as handle_request] (E:ProjectsNode-and-mongo-tutorial-masternode_modulesexpresslibrouterlayer.js:95:5) at next (E:ProjectsNode-and-mongo-tutorial-masternode_modulesexpresslibrouterroute.js:131:13) at next (E:ProjectsNode-and-mongo-tutorial-masternode_modulesexpresslibrouterroute.js:125:14) at Route.dispatch (E:ProjectsNode-and-mongo-tutorial-masternode_modulesexpresslibrouterroute.js:112:3) at Layer.handle [as handle_request] (E:ProjectsNode-and-mongo-tutorial-masternode_modulesexpresslibrouterlayer.js:95:5) at E:ProjectsNode-and-mongo-tutorial-masternode_modulesexpresslibrouterindex.js:277:22 at Function.process_params (E:ProjectsNode-and-mongo-tutorial-masternode_modulesexpresslibrouterindex.js:330:12) at next (E:ProjectsNode-and-mongo-tutorial-masternode_modulesexpresslibrouterindex.js:271:10) at Function.handle (E:ProjectsNode-and-mongo-tutorial-masternode_modulesexpresslibrouterindex.js:176:3) at router (E:ProjectsNode-and-mongo-tutorial-masternode_modulesexpresslibrouterindex.js:46:12) at Layer.handle [as handle_request] (E:ProjectsNode-and-mongo-tutorial-masternode_modulesexpresslibrouterlayer.js:95:5) at trim_prefix (E:ProjectsNode-and-mongo-tutorial-masternode_modulesexpresslibrouterindex.js:312:13) at E:ProjectsNode-and-mongo-tutorial-masternode_modulesexpresslibrouterindex.js:280:7
This error comes when cryptography algorithm failed. Should not happen as per code ! Which Node version are you using ?
You need to change the type in Postman to json it defaults to text
Tks!
I’ve the same issue as “wffger”: my Node version is 4.1.0.
Thanks
Seriously ? Need to check it again. I ran test cases before deploying to Git, worked totally fine.
Hi Shahid, I keep getting “Cannot POST users“ in the postman when I am executing the code in server.js, why is that
What is your URL where you posting data ?
There are a lot of REST implementations out there, but what is really cool about REST that is embracing HTTP, so please don’t send your errors in response with status code 200 – this is awful. Firstly, it is harder to work with at the clientside, since if you are using promises most libraries will make a reject on promise with status code >= 400. Secondly, you dont need to have error field and constantly check with if statements, if you actually have an error.
Small things – don’t call fields of *user* model: userMail and userPassword – it is a *user* model, no need to duplicate this.
Also it is good to provide some abstraction over this, since if you will have a multiple resourses, it can feel natural to novice devoloper to copy and paste this skeleton, instead of creating reusable abstraction.
Hi Dantix,
Thanks for posting comment and suggestion.
Regarding status code 200, i was not sure that promises would reject them. I need to have a look and will update the code accordingly.
Regarding Model, and appending model name in tables i read in MSDN that is it standard in database design to use table name as prefix in columns.
The password hashing used here is very bad and wrong.
Don’t use SHA-1 for password hashing. Use a slow/variable algorithm like bcrypt and more importantly, salt your passwords.
Hi,
Thanks for comment.
Will put disclaimer and update code accordingly.
nice, but to other, make suggestions and not provoking!
All works for me except for the update function. It returns the Data updated message and the _id but doesn’t actually change the data. Any ideas? Great tutorial otherwise. I find in the mongo console I can’t update there either if I’m using the _id as the selection criteria.
It should work, i just cross check at my end.
Nice post! To complement it, take a look this cool ebook: https://leanpub.com/building-apis-with-nodejs
Good book Caio.
Loved your tutorial. Made my evening. Thank you. 🙂
Absolutely awesome! thank you!
showing me the error as while posting data
TypeError: Not a string or buffer
at TypeError (native)
at Hash.update (crypto.js:70:16)
at C:\Users\Agarwal\Desktop\sss\server.js:34:28
at Layer.handle [as handle_request] (C:\Users\Agarwal\Desktop\sss\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\Agarwal\Desktop\sss\node_modules\express\lib\router\route.js:131:13)
at next (C:\Users\Agarwal\Desktop\sss\node_modules\express\lib\router\route.js:125:14)
at Route.dispatch (C:\Users\Agarwal\Desktop\sss\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (C:\Users\Agarwal\Desktop\sss\node_modules\express\lib\router\layer.js:95:5)
at C:\Users\Agarwal\Desktop\sss\node_modules\express\lib\router\index.js:277:22
at Function.process_params (C:\Users\Agarwal\Desktop\sss\node_modules\express\lib\router\index.js:330:12)
at next (C:\Users\Agarwal\Desktop\sss\node_modules\express\lib\router\index.js:271:10)
at Function.handle (C:\Users\Agarwal\Desktop\sss\node_modules\express\lib\router\index.js:176:3)
at router (C:\Users\Agarwal\Desktop\sss\node_modules\express\lib\router\index.js:46:12)
at Layer.handle [as handle_request] (C:\Users\Agarwal\Desktop\sss\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (C:\Users\Agarwal\Desktop\sss\node_modules\express\lib\router\index.js:312:13)
at C:\Users\Agarwal\Desktop\sss\node_modules\express\lib\router\index.js:280:7
Nice guide, Thank you!
@all having trouble with the mentioned error on post.
Change your post method to:
.post(function(req,res){
var db = new mongoOp();
var response = {};
// fetch email and password from REST request.
// Add strict validation when you use this in Production.
db.userEmail = req.body.userEmail;
// Hash the password using SHA1 algorithm.
db.userPassword = require(‘crypto’)
.createHash(‘sha1’)
.update(req.body.userPassword)
.digest(‘base64’);
db.save(function(err){
// save() will run insert() command of MongoDB.
// it will add new data in collection.
if(err) {
response = {“error” : true, “message” : “Error adding data”};
} else {
response = {“error” : false, “message” : “Data added”};
}
res.json(response);
});
});
and post your data as JSON(application/json)
By
Shahid Thank you for this nice tutorial. Please can you update the PUT methods it does works.
Change userEmail and UserPassowrd to simple email and password as follow
if(req.body.email !== undefined) {
// case where email needs to be updated.
data.userEmail = req.body.email;
}
if(req.body.password !== undefined) {
// case where password needs to be updated
data.userPassword = req.body.password;
}
Thank you
Awesome tutorial man.
Thanks man 🙂
Hello, when I use POST or PUT, Postman displays okay message but POST only and always inserts
{
“_id”: “5798bf7223e70e3817b61746”,
“__v”: 0
}
no email/password etc, just this above data is inserted.
and PUT doesn’t make any change..
Could there be change between some versions?
Thank you in advance!
same problem here
same problem
Thanks man, Awesome tutorial…
Only the below data is inserted in the mongodb
{
“error”: false,
“message”: [
{
“_id”: “57ed27d9fbda82807c8db0d3”,
“__v”: 0
},
{
“_id”: “57ed2845fbda82807c8db0d4”,
“__v”: 0
}
]
}
The email and password is not inserting in the POST Call.. Help pls
woo…it works..!!thank you man..!!!
To anyone who is having trouble with the database only saving “_id” and “__v” fields or the “TypeError: Not a string or buffer” error – In Postman’s Body tab, where you insert the JSON to add a new user, in addition to selecting the ‘raw’ option, set the data type as JSON, instead of Text.
if we use mysql then it will be fine?
Yes, you can.
Look over this tutorial with MySQL version.
Nice tutorial!
It has one little mistake at the end:
if(err) {
response = {“error” : true,”message” : “Error deleting data”};
} else {
response = {“error” : true,”message” : “Data associated with “+req.params.id+”is deleted”};
Please change else branch to this one: response = {“error” : false,”message” : “Data associated with “+req.params.id+”is deleted”};
.. just to be consistent 🙂
Thanks!
Thanks for pointing it out.
Very nice tutorial! I’m a beginner in MongoDB but I learned a lot from your tutorials. Thank you very much and keep up the good work! 🙂
A few things to point out on this post for anyone else learning.
1) “var mongoOp = require(“./models/mongo”);” should be “var mongoOp = require(“./model/mongo”);” if your naming your folder model.
2) Not specifying json when POSTing on postman, even though we should kinda know that.
3) “mongoose.model(‘user_login’,userSchema);” should be “mongoose.model(‘users’,userSchema);” since were using “router.route(“/users”)” during GET.
4) When using POST, it should be mentioned to define the content-type “application/json” on postman under headers because not everyone knows out of the gate.
It’s still a great article though, thanks!
how do I make versions in my API and add authentications like sendgrid
how to get some required data from mongoDB on postman
using model class
for example i have 20 parameters but i went to get according to my requirements how??