Mongo DB usage in Node

From Logic Wiki
Jump to: navigation, search

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

Update Operators

 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