MongoDB is a No (only) SQL database system manger.
MongoDB stores information in documents instead of tables.
Queries are written in json format.
Although No-SQL databases are schema-less, you can use schemas to describe the documents stored in the database.
Mongoose is a NodeJS package that eases the interaction with MongoDB by means of schemas.
To install MongoDB is OS dependent. Take a look at Install MongoDB
MongoDB provides a shell to interact with the MongoDB manager, to lauch it, just type mongo in a console.
$ mongo
MongoDB shell version: 3.2.0
connecting to: test
By default, when you start the Mongo shell the test database is automatically selected. If you want to use another one type:
mongo catalog
MongoDB shell version: 3.2.0
connecting to: catalog
To see the databases in the MongoDB manager:
> show dbs
local 0.000GB
To change/create to a particular database:
> use catalog
switched to db catalog
To see the collections in a database:
> show collections
We have no products in the collection yet. Let's add the first product:
> db.products.save({"id":"1", "name":"USB drive", "price":10})
WriteResult({ "nInserted" : 1 })
>
To find all documents in the collection:
> db.products.find()
{ "_id" : ObjectId("568b64ed3d89d76b0731ec76"), "id" : "1", "name" : "USB drive", "price" : 10 }
Note the _id attribute, its an internal key for this particular document in the database.
To update an existing document in the database:
> db.products.update({"id":"1"}, {$set:{"price":11}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
Check the update using:
> db.products.find()
{ "_id" : ObjectId("568b64ed3d89d76b0731ec76"), "id" : "1", "name" : "USB drive", "price" : 11 }
Alternatively, you can try to find just one document:
> db.products.findOne();
{
"_id" : ObjectId("568b70fc3d89d76b0731ec77"),
"id" : "1",
"name" : "USB drive",
"price" : 10
}
To remove a particular document from the database:
> db.products.remove({"id":"1"})
WriteResult({ "nRemoved" : 1 })
Try to find it out again:
> db.products.find()
No documents are reported now.
The basic CRUD operations in MongoDB are:
Operation | MongoDB command |
---|---|
Create | db.collection.save() |
Retrieve | db.collection.find() |
Update | db.collection.update() |
Delete | db.collection.remove() |
You can remove an entire database:
use catalog
db.dropDatabase()
You can quit the mongo console typing:
exit
You can check a complete introduction in Getting started with MongoDB.
Mongoose is an object modelling framework for MongoDB.
We define schemas in Mongoose that ease to write code.
First, let's install it in our application:
$npm install --save mongoose
Now, we need a connection to the MongoDB database in NodeJS.
To organize the code of our project, let's create a new folder in our products express project, name it model. Create a file named db.js and type the following code in it:
var mongoose = require("mongoose");
mongoose.connect("mongodb://localhost/catalog");
var db = mongoose.connection;
db.on("error", console.log.bind(console, "connection error."));
db.on("open", function () {
console.log("Mongodb connected");
});
module.exports = mongoose;
Note the last code line, this means that we are exposing the mongoose variable to be used in any other nodejs file.
Now, let's define the schema for our products. Create a new file, name it as product.js and type in it:
var db = require("./db");
var Product = db.model('Product', {
id: {type: String, required: true},
name: {type: String, require: true},
price: {type: Number, require: true}
});
module.exports = Product;
Note the last line of code again, we are exposing the Product variable to be used by any other nodejs file.
Let's use our MongoDB connection and schema. First, lets import the Product module, at the begining of our index.js file type:
var Product = require("./model/product")
Now, the code to find out a product by its id:
app.get("/catalog/:id", function(req, res, next) {
var idProduct = req.params.id;
Product.findOne({id: idProduct}, function(err, product) {
if(err) {
res.status(500);
next("Internal server error.");
} else if(product == null) {
res.status(404); // Not found
next("No product with code " + idProduct + " found.");
} else {
res.status(200);
res.json(product);
}
});
});
Although the function we are using is Product.findOne(json, function(err, doc)), this is not a MongoDB function but the wrapper function by Mongoose.
You can check that it works using Postman.
Let's see how to retrieve all products in the database:
app.get("/catalog", function(req, res) {
var stream = Product.find().stream();
var results = {};
stream.on('data', function(doc) {
results[doc.id] = doc;
}).on("error", function(err) {
res.status(500);
next(err);
}).on('close', function() {
res.status(200);
res.json(results);
});
});
Here, we are using find().stream() instead of just find().
find() returns a javascript array with al documents matching the query condition.
But, we want to return an associative map, so we need some control. We achieve this control by means of a stream.
Exercise
Re-code the REMOVE operation to delete an existing product(resource) in the database using Mongoose
app.delete("/catalog/:id", function(req, res, next) {
....
}
Hints: if you try Product.remove({"id": idProduct}, function(err, result) {
Try to cover all anomalous results:
Exercise
Re-code the CREATE operation to create a new product(resource) in the database using Mongoose.
app.post("/catalog", function(req, res, next) {
....
}
Try to cover all anomalous results:
Exercise
Re-code the UPDATE operation to update an existing product(resource) in the database using Mongoose.
app.put("/catalog/:id", function(req, res, next) {
....
}
Try to cover all anomalous results:
You are now able to code the basic CRUD operation for a web application using a NoSQL database.
All data of your web application is now persisted to a database, no piece of information will be lost.