1 Introduction to MongoDB
MongoDB is a NoSQL Database.
Instead of storing data in the form of table and rows, in mongoDB data in stored in the form of objects.
Mongoose is ODM, which makes it easier to communicate with MongoDB.
In this series we will learn about
MongoDB and Mongoose
CRUD application
and a testing framework called Mocha.
2 Installing MongoDB Locally & connecting to MongoDB
-
npm init
-- to track the dependencies. - Install mongoose
npm install mongoose --save
- Connecting to database: Mongoose do not automatically knows about database. we've to tell it explicitly.
//connection.js
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/testaroo');
mongoose.connection.once('open', function(){
console.log('Connection is made');
}).on('error', function(error){
console.log('Connection error', error);
})
3 Models and Collection
File: models/marioChar.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const MarioCharSchema = new Schema({
name: String,
weight: Number
})
const MarioChar = mongoose.model('mariochar', MarioCharSchema)
module.exports = MarioChar;
// Now we can do the following
// var myChar = new MarioChar({ name: "Rayan", weight: 100 });
4 Introduction to Mocha testing
Mocha is a testing framework.
We use it to perform within our application
To make sure everything works correctly
First install Mocha npm install mocha --save
Keep the test script demo_test.js
to a folder /test
.
demo_test.js
const mocha = require('mocha');
const assert = require('assert');
describe('Some demo tests', function(){
//Create tests
it('adds two numbers together', function(){
assert(2+3===5)
})
})
Set the test
property to mocha
in package.json
and run npm run test
5 Saving data to MongoDB
const mocha = require('mocha');
const assert = require('assert');
const MarioChar = require('../models/mariochar');
describe('Some demo tests', function(){
//Create tests
it('Saves a record to the database', function(done){
var character = new MarioChar({
name: "Mario",
})
character.save().then(function(){
assert(character.isNew === false)
done();
})
})
})
character.save().then(function(){
assert(character.isNew === false)
done();
})
The above function saves the character
in the database.
character.isNew
returns true
when the object is created but not present in the database.
and returns false
when the object is found in the database.
As save
is an asynchronous function, to perform next tests we have to explicitly tell when it is finished through done
method.
Using ES6 promise instead using mogoose's own promise
const mongoose = require('mongoose');
// Using ES6 promise instead mogoose's promise
mongoose.Promise = global.Promise
// Connect to mongodb
mongoose.connect('mongodb://localhost/testaroo');
mongoose.connection.once('open', function(){
...
}).on('error', function(error){
...
})
At this point our test is being ran even before the connection is established.
To do that we have to put our connection code inside before
before(function(done){
mongoose.connect('mongodb://localhost/testaroo');
mongoose.connection.once('open', function(){
console.log('Conneciton is made');
done();
}).on('error', function(error){
console.log('Connection error', error);
})
})
Note that we've also used done to explicitly tell when the connection is established.
6 Dropping a Collection
To drop a collection:
mongoose.connection.collections.mariochars.drop()
note that we're writing mariochars
(pluralized) and not mariochar
but we've declared the collection as mariochar
. This is the way mongodb works.
To drop the collection before every test so that the result of one test do not affect the other test by using beforeEach
const mongoose = require('mongoose');mongoose.Promise = global.Promise
before(function(done){
// Connect to mongodb
...
})
beforeEach(function(done){
mongoose.connection.collections.mariochars.drop()
done()
})
7 Finding Records
To search we can use find
or findOne
method to the model.
MarioChar.findOne({ name: "Mario"}).then(result => {
...
})
This code, finds the first match where name==="Mario"
Our finding_test.js file is
const assert = require('assert');
const MarioChar = require('../models/mariochar');
describe('Some demo tests', function(){
beforeEach(function(done){
var character = new MarioChar({
name: "Mario",
})
character.save().then(function(){
assert(character.isNew === false)
done();
})
})
//Create tests
it('Finding a record form the database', function(done){
MarioChar.findOne({ name: "Mario"}).then(result => {
assert(result.name === "Mario")
done();
})
})
})
8 ObjectId
To retrieve data by ID from the collection:
MarioChar.findOne({ _id: character._id }).then(result => {
assert(result._id === character._id)
done();
})
But the above code is not going to work as
result._id===character._id
is going to return false
as
result._id
is of type ObjectID
and character._id
is of type String
. So we've to convert both of them to String and then compare.
result._id.toString()===character._id.toString()
will return true
9 Deleting Record
Mongoose has 3 records to delete records
char.remove()
-
MarioChar.remove()
Inside the bracket we are going to pass the options -
MarioChar.findOneAndRemove()
Inside the bracket we're going to pass the options
Use of findOneAndRemove()
MarioChar.findOneAndRemove({ name:"Mario" }).then(function(){
MarioChar.findOne({ name:"Mario" })
})
10 Updating Record
Various mongoose methods
- char.update()
- MarioChar.update()
- MarioChar.findOneAndUpdate()
// Saving the data
character = new MarioChar({
name: "Mario",
weight: 60
})
character.save().then(function(){
...
})
// Updating the data
MarioChar.findOneAndUpdate({ name:"Mario"}, { name:"new_name"}).then(function(){
MarioChar.findOne({ name:"Mario" }).then(result => {
...
})
})
The the new changes will be injected and this will not overwrite the complete objects. This update results to the object:
{ name: "new_name", weight: 100 }
and not just { name: "new_name" }
11 Relational Data
Suppose, Author(name, age, books) and Book(title, pages) are two relations.
In the following way we construct it in MongoDB
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const BookSchema = new Schema({
title: String,
pages: Number
});
const AuthorSchema = new Schema({
name: String,
age: Number,
books: [BookSchema]
})
const Author = mongoose.model('author', AuthorSchema);
module.exports = Author;
books: [BookSchema]
tells us that books
property is an array where the array elements will be of the form BookSchema
12 Nesting Documents
const mongoose = require('mongoose');
const assert = require('assert')
const Author = require('../models/author');
describe('Nesting Documents', function(){
//Create tests
it('Create an author with sub-documents', function(done){
var pat = new Author({
name: 'Patrick Ruffus',
books:[{title:'Name of the wind', pages: 400}]
});
pat.save().then(function(){
Author.findOne({name:'Patrick Ruffus'}).then(function(record){
assert(record.books.length === 1);
done();
})
})
})
it('Add a book to an existing author', function(done){
var rus = new Author({
name: 'Ruskin Bond',
books:[{title:'The eyes have it', pages: 400}]
});
rus.save().then(function(){
Author.findOne({name:'Ruskin Bond'}).then(function(record){
record.books.push({title:"7 husband", pages:200});
record.save().then(function(){
Author.findOne({ name: 'Ruskin Bond' }).then(function(record){
assert(record.books.length===2);
done();
})
})
})
})
})
})
Top comments (0)