Mongo DB usage in Node
Setting up our database
Right, next up we are going to setup our database. We’re going to use mongodb with mongoose.
yarn add mongoose
or
npm i mongoose
in index.js
const hapi = require('hapi');
const mongoose = require('mongoose');
The next final ingredient related to our database is mlab. Instead of running mongo on our local computer, we are gonna use a cloud provider like mlab. And finally create a user for the database. That will be all we will be editing on mlab.
mongoose.connect('mongodb://<DBUserName>:<DbPassWord>@ds245680.mlab.com:<Port>/<DbName>')
mongoose.connection.once('open', ()=> {
console.log('connected to database');
})
or
mongoose.connect('mongodb://<DBUserName>:<DbPassWord>@ds245680.mlab.com:<Port>/<DbName>')
.then() => console.log('connected to database')
.catch() => console.error('Could not connect to database', err);
Schema
it's not part of mongoDb. It's related with mongoose
const courseSchema = new mongoose.Schema({
name: String,
author: String,
tags:[ String ],
date: Date, // or with a default value -> date: {type:Date, default: Date.now }
isPublished: Boolean
});
Schema Types
- String
- Number
- Date
- Buffer
- Boolean
- ObjectID
- Array
Schema to Model
const Course = mongoose.model('Course', courseSchema);
using model
const course = new Course({
name : 'Node.js Course',
author : 'Ali',
tags : ['node', 'backend'],
isPublished : true
});
Save object to DB
async function createCourse(){
const courseSchema = new mongoose.Schema({
name: String,
author: String,
tags:[ String ],
date: Date, // or with a default value -> date: {type:Date, default: Date.now }
isPublished: Boolean
});
const result = await course.save();
console.log(result);
}
createCourse();
Query Database
async function getCourses(){
const courses = await Course.find();
// const courses = await Course.find({ author: 'Ali', isPublished: true}); // with criteria
console.log(courses);
}
getCourses();
a little bit more complex query
async function getCourses(){
const courses = await Course
.find({ author: 'Ali', isPublished: true})
.limit(10)
.sort({ name: 1}) // desc : -1
.select({name:1, tags:1});
console.log(courses);
}
getCourses();
Comparison Operators
- eq : equal
- ne : not equal
- gt : greater than
- gte : greater than or equal to
- lt : less than
- lte : less than or equal to
- in : in
- nin : not in
async function getCourses(){
const courses = await Course
.find({ price: {$gt: 10} }) // greater than
// .find({ price: {$gt: 10, $lt:20} }) // between 10 and 20
// .find({ price: {$in: [10,15, 20]} }) // in 10,15 and 20
.limit(10)
.sort({ name: 1}) // desc : -1
.select({name:1, tags:1});
console.log(courses);
}
getCourses();
Logical Operators
- or
- and
async function getCourses(){
const courses = await Course
.find()
.or([{author:'Ali'},{ isPublished:true}]) //-> author is Ali or published
.limit(10)
.sort({ name: 1}) // desc : -1
.select({name:1, tags:1});
console.log(courses);
}
getCourses();
Regular Expressions
- ^ : starts with /^Ali/
- $ : ends with /Iybar$/
- i : case insensitive /Iybar$/i
- .*something.* : Contains /.*yba.*/
async function getCourses(){
const courses = await Course
.find( {author:/^Ali/ })
.limit(10)
.sort({ name: 1}) // desc : -1
.select({name:1, tags:1});
console.log(courses);
}
getCourses();
Count
async function getCourses(){
const courses = await Course
.find( {author:/^Ali/ })
.limit(10)
.sort({ name: 1}) // desc : -1
.count()
console.log(courses);
}
getCourses();
Paging
async function getCourses(){
const pageNumber =2;
const pageSize = 10;
const courses = await Course
.find( {author:/^Ali/ })
.skip(pageNumber -1) * pageSize)
.limit(pageSize)
.sort({ name: 1}) // desc : -1
.select({name:1, tags:1});
console.log(courses);
}
getCourses();
Update with QueryFirst Approach
async function updateCourses(id){
const courses = await Course.findById(id);
if((!course) return;
course.isPublished = true;
course.author = 'Another Author';
// Alternatively
// course.set({
// isPublished:true,
// author:'Another Author'
// });
const result = await course.save();
console.log(courses);
}
updateCourses('1234-01-12123....');
Update with Update First Approach
async function updateCourses(id){
const result = await Course.update({_id:id}, { // for more records ({ isPublished:false })
$set: {
author:'Veli',
isPublished:false
}
});
console.log(result);
}
updateCourses('1234-01-12123....');
FindByIdAndUpdate
This returns the original object before the update
async function updateCourses(id){
const result = await Course.findByIdAndUpdate (id, { // for more records ({ isPublished:false })
$set: {
author:'Veli',
isPublished:false
}
});
console.log(result);
}
updateCourses('1234-01-12123....');
In order to get updated object we pass another arguement { new : true}
async function updateCourses(id){
const result = await Course.findByIdAndUpdate (id, { // for more records ({ isPublished:false })
$set: {
author:'Veli',
isPublished:false
}
},{ new : true});
console.log(result);
}
updateCourses('1234-01-12123....');
Remove a document
async function removeCourses(id){
const result = await Course.deleteOne({ _id:id})
console.log(result);
}
removeCourses('1234-01-12123....');
it returns null if there is no such record exists
Remove many documents
async function removeCourses(id){
const result = await Course.deleteMany({ isPublished:false})
console.log(result);
}
removeCourses('1234-01-12123....');
Mongoose Data Validation
const courseSchema = new mongoose.Schema({
name: { type: String, required:true},
author: String,
tags:[ String ],
date: Date, // or with a default value -> date: {type:Date, default: Date.now }
isPublished: Boolean
});
if the data to be saved is not valid promise returns error.
Manually Triggering Validation
async function createCourse(){
const courseSchema = new mongoose.Schema({
author: String,
tags:[ String ],
date: Date, // or with a default value -> date: {type:Date, default: Date.now }
isPublished: Boolean
});
await course.validate();
// or
course.validate((err) => {
if(err) {
.... do something
}
});
console.log(result);
}
createCourse();
Built-in Validation
name: {
type: String,
required:true,
minlength:5,
maxlength:255,
match:/regex/,
enum: ['web', 'mobile', 'network']
},
price:{
type:Number,
min:10,
max:200
}
Custom Validators
const courseSchema = new mongoose.Schema({
name: { type: String, required:true},
author: String,
tags:[ String ],
date: Date, // or with a default value -> date: {type:Date, default: Date.now }
isPublished: Boolean
price: {
type:Number,
required:function(){ return this.isPublished;} // it is required if isPublished -> can't use arrow function here because of this
}
});
if the data to be saved is not valid promise returns error.
tags: {
type: Array,
validate:{
validator: function(v) {
return v && v.length > 0;
},
message:'Must be greater than 0'
}
}
Async Validator
isAsync : true and callbacks
tags: {
type: Array,
validate:{
isAsync : true,
validator: function(v, callback) {
setTimeout(()=> {
// do something
const result = v && v.length > 0;
callback(result)
}, 1000);
},
message:'Must be greater than 0'
}
}
Validation Errors
try {
const result = await course.save();
console.log(result);
}
catch (ex) {
for (field in ex.errors)
console.log(ex.errors[field]);
}
Schema Type Options
string
- lowercase: true
- uppercase: true
- trim: true
name: {
type: String,
required:true,
minlength:5,
maxlength:255,
match:/regex/,
enum: ['web', 'mobile', 'network'],
lowercase : true
},
getter and setter
- get: v=> Math.round(v)
- set: v=> Math.round(v)
Router Sample
router.get('/', async (req, res) => {
const genres = await Genre.find();
res.send(genres);
});
See Also : Mongo DB - Related Models