DEV Community

Cover image for Mission 2: Be a Mongoose Master
Kazi Abdur Rakib
Kazi Abdur Rakib

Posted on • Edited on

Mission 2: Be a Mongoose Master

Module 5: In-Depth Exploration of MongoDB Queries

5-0 Introduction of be a Mongoose Master

Image description

Image description

Image description

Image description

Image description

Image description

5-1-A Install MongoDB compass & No SQL Booster ( windows)

5-1-B Install MongoDB compass & No SQL Booster ( Mac & Linux)

=> https://www.mongodb.com/try/download/community

Module 6: Mastering MongoDB Aggregation & Indexing

6-0 Introduction of powerful aggregation framework

Image description

6-1 $match , $project aggregation stage

db.test.aggregate( [

   // Stage 1: 
   {
      $match: { gender: "Male" , age: {$lt: 30}}
   },

  // Stage 2: 
  {
      $project: {name:1, age:1,gender:1} 
  }

] )
Enter fullscreen mode Exit fullscreen mode

6-2 $addFields , $out , $merge aggregation stage

=>
=>

//6-0 Introduction of powerful aggregation framework
db.test.aggregate( [

  // Stage 1: 
  {
      $match: { gender: "Male" , age: {$lt: 30}}
  },

  // Stage 2: 
  {
      $addFields: {course: "level-2"} //addfileds works temporary to add a new field
  },

  {
      $project: {course:1}
  },
//   {
//       $out: "course-students" //out use for create a new collection and use addfields temporaty data to merge in a new collection collection
//   },
  {
      $merge: "test" // merge my new field in the test collection
  }

] )
Enter fullscreen mode Exit fullscreen mode

6-3 $group , $sum , $push aggregation stage

//group
db.test.aggregate( [
    //stage-1
    {$group:{_id:"$gender"}}
] )
Enter fullscreen mode Exit fullscreen mode
//count sum
db.test.aggregate([
    //stage-1
    { $group: { _id: "$address.country", count: {$sum: 1 }} }
])

Enter fullscreen mode Exit fullscreen mode
//use push
db.test.aggregate([
    //stage-1
    { $group: { _id: "$address.country", count: {$sum: 1 }, showMeName:{$push:"$name"}} }
])
Enter fullscreen mode Exit fullscreen mode
//use $$ROOT
db.test.aggregate([
    //stage-1
    {
        $group: {
            _id: "$address.country",
            count: { $sum: 1 },
            fullDoc: { $push: "$$ROOT" }
        }
    },
    //stage-2==> want to send only name email and phone
    {
        $project: {
            "fullDoc.name":1,
            "fullDoc.email":1,
            "fullDoc.phone":1,
        }
    }
])
Enter fullscreen mode Exit fullscreen mode

6-4 explore more about $group & $project

//total salary
db.test.aggregate([
    //stage-1
    {
        $group: {
            _id: null,
            totalSalary : {$sum: "$salary"}
        }
    },
])

Enter fullscreen mode Exit fullscreen mode
db.test.aggregate([
    //stage-1
    {
        $group: {
            _id: null,
            totalSalary: { $sum: "$salary" }, // total salary
            maxSalary: { $max: "$salary" }, // maximum salary
            minSalary: { $min: "$salary" }, // minium salary
            avgSalary: { $avg: "$salary" } // average salary
        }
    },
    //stage-2
    {
        $project: {
            totalSalary: 1,
            maxSalary: 1,
            minSalary: 1,
            avgSalary: 1,
            averageSalary: "$avgSalary",  // or we can also write 
            rangeMaxMinusMin:{$subtract:["$maxSalary","$minSalary"]} //max salary minus min salary
        }
    }
])
Enter fullscreen mode Exit fullscreen mode

6-5 Explore $group with $unwind aggregation stage

Image description

db.test.aggregate([
    //stage-1
    {
        $unwind: "$interests"
    },
    //stage-2
    {
        $group: { _id: "$age", interestperage:{$push:"$interests"}}
    }
])
Enter fullscreen mode Exit fullscreen mode

6-6 $bucket, $sort, and $limit aggregation stage

db.test.aggregate([
    //stage-1
    {
        $bucket: {
            groupBy: "$age",
            boundaries: [20, 40, 60, 80],
            default: "80 er upor bura gula",
            output: {
                count: { $sum: 1 },
                sobarname: { $push: "$name" }, // sobar name nisi
                allDocuments: { $push: "$$ROOT" } // ARRAY of objects a all documets nia nisi
            }
        }
    },
    //stage-2
    {
        $sort: {count:-1}
    },
    //stage-3 => if i want i can output only 2 documents
    {
        $limit: 2
    },
    //stage-4
    {
        $project: {count:1}
    }
])
Enter fullscreen mode Exit fullscreen mode

6-7 $facet, multiple pipeline aggregation stage

Image description


db.test.aggregate([
    {
        $facet: {
            //pipeline-1
            "friendscount": [
                {
                    $unwind: "$friends"
                },
                {
                    $group: { _id: "$friends", count: { $sum: 1 } }
                }
            ],
            //pipeline-2
            "educationCount": [
                {
                    $unwind: "$education"
                },
                {
                    $group: { _id: "$education", count: { $sum: 1 } }
                }

            ],
            //pipeline-3
            "skilslcouunt": [
                {
                    $unwind: "$skills"
                },
                {
                    $group: { _id: "skills", count: { $sum: 1 } }
                }

            ]
        }
    }

])
Enter fullscreen mode Exit fullscreen mode

6-8 $lookup stage, embedding vs referencing

Image description

Image description

db.orders.aggregate( [
   {
     $lookup:
       {
         from: "test",
         localField: "userId",
         foreignField: "_id",
         as: "user"
       }
  }
] )
Enter fullscreen mode Exit fullscreen mode

6-9 What is indexing, COLLSCAN vs IXSCAN

Image description

Image description

6-10 Explore compound index and text index

db.getCollection("massive-data").createIndex({ age: 1 })

Enter fullscreen mode Exit fullscreen mode

Image description

Image description

Image description

Module 7:Mastering The Foundation Of Express

7-1 What is nodejs , a high level overview of node.js

7-2 What is module, commonjs vs esm

=>local1.js
const add = (parm1, parm2)=> parm1+parm2
const a=10

module.exports={
    add,
    a
}

// console.log(module)

//built-in-modules-1
const path = require("path")
console.log(path.dirname("/home/rakib/Desktop/1.NextLevelWebDevelopment/ts/module1/dist/inde.js"))

//built-in-modules-2
const path = require("path")
console.log(path.parse("/home/rakib/Desktop/1.NextLevelWebDevelopment/ts/module1/dist/inde.js"))

=>local2.js
const add = (parm1, parm2,parm3)=> parm3+parm1+parm2
const a=10

module.exports={
    add,
    a
}
module.exports=add
=>index.js
const {add,a} = require('./local1')
const {add:add2,a:a2} = require('./local2')
console.log(a)

Enter fullscreen mode Exit fullscreen mode

Image description

const fs = require('fs')

//reading a file text
const readText= fs.readFileSync('./texts/read.txt', 'utf-8')

console.log(readText)

//writting a text
const writternText = fs.writeFileSync('./texts/write.txt', readText + 'Thsi is rakib')
console.log(writternText);
Enter fullscreen mode Exit fullscreen mode

7-3 File System Module , synchronous vs asynchronous

const fs = require('fs')

//reading text asynchronously

fs.readFile('./texts/read.txt', 'utf8', (err, data) => {
    if (err) {
        throw Error('error reading')
    }
    // console.log(data);

    // write text file asynchornosuly
    fs.writeFile('./texts/read2.txt',data, 'utf8', (err) => {
        if (err) {
            throw Error('error writing')
        }
        console.log('The file has been saved!');
    });
});


Enter fullscreen mode Exit fullscreen mode

7-4 Event driven architecture, create your own events

const EventEmitter = require('events');
const myEmitter = new EventEmitter();

// First listener
myEmitter.on('event', () =>{
  console.log('Helloooo! first listener');
});
// Second listener
myEmitter.on('event', (arg1, arg2) => {
  console.log(`event with parameters ${arg1}, ${arg2} in second listener`);
});
// Third listener
myEmitter.on('event', (...args) =>{
  const parameters = args.join(', ');
  console.log(`event with parameters ${parameters} in third listener`);
});

// console.log(myEmitter.listeners('event'));

myEmitter.emit('event', 1, 2, 3, 4, 5);
Enter fullscreen mode Exit fullscreen mode

7-5 Stream and buffer, create your own server

const http = require('http');

// Create a local server to receive data from
const server = http.createServer();

// Listen to the request event
server.on('request', (request, res) => {
  //   res.writeHead(200, { 'Content-Type': 'application/json' });
  console.log(request)

  res.end(JSON.stringify({
    data: 'Hello World!',
  }));
});

server.listen(5000, () => {
  console.log(`server is listening on port 5000 {$port}`)
});

//===> to run node filename.js

Enter fullscreen mode Exit fullscreen mode

7-5 Stream and buffer, create your own server

const http = require('http');
const fs = require('fs');

// Create a local server to receive data from
const server = http.createServer();

// Listen to the request event
server.on('request', (request, res) => {

  if (request.url === '/read-file' && request.method === 'GET');

//straming file reading
    const readblestram = fs.createReadStream(process.cwd() + '/texts/read.txt');

    readblestram.on('data', (buffer) => {
      res.statusCode = 200;
      res.write(buffer);
    });

    readblestram.on('end', () => {
      res.statusCode = 200;
      res.end('HAPPY ENDING');
    });

    readblestram.on('error', (error) => {
      console.log(error);
      res.statusCode=500;
      res.end('something went wrong');
    });

});

server.listen(5000, () => {
  console.log(`server is listening on port 5000 {$port}`)
});
Enter fullscreen mode Exit fullscreen mode

7-6 Installing express, typescript

npm init
yarn add express
yarn add -D typescript
tsc --init
yarn add -D @types/node
yarn add -D @types/express
yarn add -D nodemon
Enter fullscreen mode Exit fullscreen mode
"rootDir": "./src/",
"outDir": "./dist/",     
Enter fullscreen mode Exit fullscreen mode
tsc -w
Enter fullscreen mode Exit fullscreen mode

Image description

"start-dev" : "nodemon ./dist/app/server.js",
rakib@pop-os:~/Documents/project-1/dist/app$ yarn start-dev    
Enter fullscreen mode Exit fullscreen mode
//app.ts
// const express = require('express')
import express from 'express';
const app = express();
const port = 3000;

app.get('/', (req, res) => {
    res.send('Hello World!')
})

export default app;
Enter fullscreen mode Exit fullscreen mode
//server.ts
import { Server } from 'http';
import app from './app';

const PORT = 5000;

let server: Server;


async function bootstrap() {
    server = app.listen(PORT, () => {
        console.log(`Example app listening on port ${PORT}`)
    });
}

bootstrap();
Enter fullscreen mode Exit fullscreen mode

Image description

Image description

7-7 What is parsers, request and response object

tsc

import express, {Request, Response} from 'express';

app.get('/', (req: Request, res:Response) => {
Enter fullscreen mode Exit fullscreen mode
yarn add -D nodemon
"start-dev": "nodemon ./dist/app/server.js",
Enter fullscreen mode Exit fullscreen mode
//perser
app.use(express.json());
app.use(express.text());
Enter fullscreen mode Exit fullscreen mode
app.post('/', (req: Request, res:Response) => {
    console.log(req.body);
    res.json({
        message: "suffesfully done"
    })
})

Enter fullscreen mode Exit fullscreen mode

7-8 middleware in express.js

// const express = require('express')
import express, {Request, Response, NextFunction } from 'express';

const app = express();
const port = 3000;

//perser
app.use(express.json());
app.use(express.text());



// Your custom "middleware" function:
const logger = (req: Request, res: Response, next: NextFunction): void => {
    console.log(req.url, req.method,req.hostname);
    next();
}


//==> for this: http://localhost:5000/123/12
app.get('/:id/:subid',logger, (req: Request, res: Response) => {
    console.log(req.params);
    res.send('param all!')
})

//==> for tthis=> http://localhost:5000?email=karakib2k18@gmail.com&name=rakib
app.get('/',logger, (req: Request, res: Response) => {
    console.log(req.query);
    console.log(req.query.name);
    console.log(req.query.email);
    res.send('query param!')
})

app.post('/',logger, (req: Request, res: Response) => {
    console.log(req.body);
    res.json({
        message: "suffesfully done"
    })
})

export default app;
Enter fullscreen mode Exit fullscreen mode

7-9 Routing in express.js

// const express = require('express')
import express, {Request, Response, NextFunction } from 'express';

const app = express();
const port = 3000;

//perser
app.use(express.json());
app.use(express.text());

//use router
const useRouter =  express.Router();
const courseRouter =  express.Router();

app.use("/api/v1/users", useRouter);
app.use("/api/v1/course", courseRouter);

useRouter.get("/create-user", (req: Request, res: Response) => {
    const user = req.body;
    console.log(user);
    res.json({
        success: true,
        message: "user is create successfully",
        data: user,
    })
})

courseRouter.post("/create-course", (req: Request, res: Response) => {
    const course = req.body;
    console.log(course);
    res.json({
        success: true,
        message: "course is create successfully",
        data: course,
    })
})


export default app;
Enter fullscreen mode Exit fullscreen mode

7-10 express Error Handler part 1

app.get('/',logger,  async(req: Request, res: Response, next: NextFunction) => {
    try {
        res.send(result); //=> here is worng
      } catch (error) {
        next(error); // NEXT diye global middleware a send kore dibo
      }
    console.log(req.body);

})

Enter fullscreen mode Exit fullscreen mode
// Error handling GLOBAL middleware
app.use((error: any, req: Request, res: Response, next: NextFunction) => {
    console.log(error);
    if(error){
        res.status(400).json({
            success: false,
            message: "Something went wrong",
        });
    }
  });
Enter fullscreen mode Exit fullscreen mode
app.all('*', (req: Request, res: Response) => {
    res.status(400).json({
        success: false,
        message: 'Route is not found',
    });
});
Enter fullscreen mode Exit fullscreen mode
app.get('/', logger, async (req: Request, res: Response, next: NextFunction) => {
    try {
        res.send(result); //=> here is worng
    } catch (error) {
        next(error); // NEXT diye global middleware a send kore dibo
    }
    console.log(req.body);

})

app.all('*', (req: Request, res: Response) => {
    res.status(400).json({
        success: false,
        message: 'Route is not found',
    });
});


// Error handling GLOBAL middleware
app.use((error: any, req: Request, res: Response, next: NextFunction) => {
    console.log(error);
    if (error) {
        res.status(400).json({
            success: false,
            message: "Something went wrong",
        });
    }
});
Enter fullscreen mode Exit fullscreen mode

Project-1

Module_8: Mastering the core concepts of mongoose

=> Installation: https://blog.logrocket.com/linting-typescript-eslint-prettier
=> Starter pack: https://github.com/Apollo-Level2-Web-Dev/first-project/tree/first-project-0

=> Github Link: Module 8 :
https://github.com/Apollo-Level2-Web-Dev/first-project/tree/first-project-1

8-1 Introduction to mongoose

Image description

Image description

8-2 Installing express , mongoose, typescript, dotenv ,cors

npm init -y
Enter fullscreen mode Exit fullscreen mode
  1. express
  2. mongose
  3. typescript
  4. cors
  5. dotenv to access environment virable
npm install express
npm install mongodb
npm i dotenv
npm install mongoose --save
npm install typescript --save-dev
npm i cors
tsc -init
npm i --save-dev @types/express
npm i --save-dev @types/cors
Enter fullscreen mode Exit fullscreen mode
//then to to the tsconfig.json
//find the rootdir and write: "rootDir": "./src", 
//find the outdir and write: "outDir": "./dist",  
//then open a file src and make a file app.ts in this file
//go to the package.json and write "build": "tsc" in scripts.
Enter fullscreen mode Exit fullscreen mode
//then do this for create dist file for js
npm run build
//then run js code
node ./dist/app.js
Enter fullscreen mode Exit fullscreen mode
//then listen code to server.ts from app.ts
//then go to the mongose and write it in server.ts
import mongoose from 'mongoose';

main().catch(err => console.log(err));

async function main() {
  await mongoose.connect('mongodb://127.0.0.1:27017/test');

  // use `await mongoose.connect('mongodb://user:password@127.0.0.1:27017/test');` if your database has auth enabled
}

Enter fullscreen mode Exit fullscreen mode
//then go to the mongoDB atlas and create a database in Connecting with MongoDB Driver and copy this 3. Add your connection string into your application code then save it in .env file

PORT = 5000
DATABASE_URL = mongodb+srv://admin-um:admin12345@cluster0.rp8qrq9.mongodb.net/first-project?retryWrites=true&w=majority
Enter fullscreen mode Exit fullscreen mode

Image description

fidning location of the env file
console.log(process.cwd());
rakib@pop-os:~/Documents/first-project$ node ./dist/app.js
/home/rakib/Documents/first-project

Enter fullscreen mode Exit fullscreen mode
//src/app/config/index.ts
import dotenv from 'dotenv'
import path from 'path';
dotenv.config({path: path.join(process.cwd(), '.env)')})
export default{
    port: process.env.PORT,
    database_url: process.env.DATABASE_URL,
}

///home/rakib/Documents/first-project
Enter fullscreen mode Exit fullscreen mode

8-3 Installing eslint, refactor code, fix errors using command

//server.ts
import app from "./app";
import config from "./app/config";
import mongoose from 'mongoose';

main().catch(err => console.log(err));

async function main() {
    try {
        await mongoose.connect(config.database_url as string);

        app.listen(config.port, () => {
            console.log(`Example app listening on port ${config.port}`)
        })
    } catch (err) {
        console.log(err)
    }
}
Enter fullscreen mode Exit fullscreen mode
//app.ts
import express,{Application, Response, Request} from 'express'
const app: Application = express()

app.get('/', (req:Request, res:Response) => {
  res.send('Hello World!')
})

console.log(process.cwd());
export default app;
Enter fullscreen mode Exit fullscreen mode

//istalling eslint
//now to to the tsconfig.json in vscode and paste this code

  "include": ["src"], // which files to compile
  "exclude": ["node_modules"], // which files to skip

//now install this code in command line:
npm install eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev
npx eslint --init

Enter fullscreen mode Exit fullscreen mode

Image description


Youll find that some files dont need to be linted at all, such as your dist folder, so you can prevent linting by creating a .eslintignore file and adding the folders or files you want to ignore:

//=> .eslintignore file create
node_modules
dist

// now go to the packeage.json and add this file in script:
    "lint": "eslint src --ignore-path .eslintignore --ext .ts",

Enter fullscreen mode Exit fullscreen mode
//for checking
npx eslint src
// 2nd way
npm run lint
//3rd way
npx eslint src .
//to fix the problem write this command in sciprt
    "lint:fix":"npx eslint src --fix",
to run this write this=>npm run lint:fix
Enter fullscreen mode Exit fullscreen mode
// go to the eslint.json and add this file in the last
    "rules": {
        "no-unused-vars": "error",
        "no-unused-expressions": "error",
        "prefer-const": "error",
        "no-console": "warn",
        "no-undefined": "error"
    },
    "globals": {
        "dataLayer": "readonly"
    }
Enter fullscreen mode Exit fullscreen mode
npm run lint
Enter fullscreen mode Exit fullscreen mode

8-4 Install prettierts-node-dev,fix formatting issues

*### Integrating Prettier *
Run the following command in the terminal:

npm install --save-dev prettier
Enter fullscreen mode Exit fullscreen mode
// now a create a file of this=> .prettierrc.json
{
  "semi": true,
  "singleQuote": true

}

Enter fullscreen mode Exit fullscreen mode

Next, we are going to start formatting our code using Prettier in the command line:

npx prettier --write src/app.ts
# src/index.ts 37ms
Enter fullscreen mode Exit fullscreen mode

// package.json

{
  // ...
  "scripts": {
  // ...others code..
    "prettier": "prettier --ignore-path .gitignore --write \"./src/**/*.+(js|ts|json)\"",
  },
  // ...
}

Enter fullscreen mode Exit fullscreen mode
//to run prettier
npm run prettier

Enter fullscreen mode Exit fullscreen mode
// settings.json =>tthis is vscode setting then paste
{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  ...
}

Enter fullscreen mode Exit fullscreen mode

=>install direct extesnion app

Image description

Image description

*Avoiding conflicts when working with ESLint and Prettier
*

npm install --save-dev eslint-config-prettier
Enter fullscreen mode Exit fullscreen mode
// .eslintrc
{
  // HERE and relace with previous estends
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "prettier"
  ],
}

Enter fullscreen mode Exit fullscreen mode
  "scripts": {
    "prettier": "prettier --ignore-path .gitignore --write \"./src/**/*.+(js|ts|json)\"",
    "prettier:fix": "npx prettier --write src",
  },

Enter fullscreen mode Exit fullscreen mode
npm run prettier:fix
Enter fullscreen mode Exit fullscreen mode

Image description

npm run build
Enter fullscreen mode Exit fullscreen mode
// first npm run build, then do node ./dist/server.js, its so boring, so we will write a snipted to do this easily

//now isntall ts-node-dev => for making development faster
npm i ts-node-dev 
npm i ts-node-dev --save-dev

//auto response and making transparent
ts-node-dev --respawn --transpile-only src/server.ts
Enter fullscreen mode Exit fullscreen mode
//in package.json
"scripts": {
    "start:prod": "node ./dist/server.js",
    "start:dev": "ts-node-dev --respawn --transpile-only src/server.ts",
    "build": "tsc",
Enter fullscreen mode Exit fullscreen mode
// .env file for developemnt
NODE_ENV= development
PORT=5000
DATABASE_URL= mongodb+srv://admin:admin@cluster0.rp8qrq9.mongodb.net/?retryWrites=true&w=majority
Enter fullscreen mode Exit fullscreen mode

8-5 Software design pattern , mvc vs modular, create an interface

Image description

Image description

Image description

Image description

Image description

Image description

Image description

=> go to this site: https://mongoosejs.com/docs/typescript.html


8-8 Create route , service and controller

Image description

Image description

Advanced CRUD with express, mongoose and typescript

9-1 Introduction to validation

Image description

Image description

9-2 How to do custom validation

9-3 How to validate using validator and Joi package

npm i validator
npm i -D @types/validator
import validator from 'validator';
Enter fullscreen mode Exit fullscreen mode
import validator from 'validator';
Enter fullscreen mode Exit fullscreen mode
    validate: {
      validator: function (value: string) {
        // Capitalize the first letter and check if it remains the same
        const firstNameStr = value.charAt(0).toUpperCase() + value.slice(1);
        return firstNameStr === value;
      },
      message: '{VALUE} is not in capitalized format',
    },
Enter fullscreen mode Exit fullscreen mode
    validate: {
      validator: (value: string) => validator.isEmail(value),
      message: '{VALUE} is not valid',
    },
Enter fullscreen mode Exit fullscreen mode

Joi

npm i joi
import Joi from 'joi';

Enter fullscreen mode Exit fullscreen mode
    if (error) {
      res.status(500).json({
        success: false,
        message: 'joi validation went wrong',
        data: error.details,
      });
    }
Enter fullscreen mode Exit fullscreen mode
    const { student: studentData } = req.body;

    // data validation using joy
    const { error, value } = studentValidationSchema.validate(studentData);
    //will call service funditon to send this data
    const result = await StudentServices.createStudentIntoDB(value);
    // // console.log({ error }, { value });

    if (error) {
      res.status(500).json({
        success: false,
        message: 'joi validation went wrong',
        data: error.details,
      });
    }
Enter fullscreen mode Exit fullscreen mode

9-5 How to validate using zod

npm install zod 
Enter fullscreen mode Exit fullscreen mode
    const { student: studentData } = req.body;

    //------------------------------
    // //==> data validation using zod=> IMPORTANT
    const zodvalidatedData = studentValidationSchema.parse(studentData);

    const result = await StudentServices.createStudentIntoDB(zodvalidatedData);

    //-------------------------------
Enter fullscreen mode Exit fullscreen mode

9-6 Implement a custom instance method

const createStudentIntoDB = async (studentData: Student) => {
  //   //by noramal as usal method
  // const result = await studentModel.create(studentData);

  //static method create
  const student = new studentModel(studentData);
  const result = await student.save(); //built in instance
  return result;
};
Enter fullscreen mode Exit fullscreen mode
export type StudentMethods = {
  isUserExits(id: string): Promise<Student>;
};

export type StudentModel = Model<
  Student,
  Record<string, never>,
  StudentMethods
>;

Enter fullscreen mode Exit fullscreen mode

9-7 Implement a custom static method

//creating a custom static method

export interface StudentModel extends Model<TStudent> {
  // eslint-disable-next-line no-unused-vars
  isUserExists(id: string): Promise<TStudent | null>;
}
Enter fullscreen mode Exit fullscreen mode
const studentSchema = new Schema<TStudent, StudentModel>(

Enter fullscreen mode Exit fullscreen mode
// create cusitom static method

studentSchema.statics.isUserExists = async function (id: string) {
  const existingUser = await Student.findOne({ id });
  return existingUser;
};
Enter fullscreen mode Exit fullscreen mode
  // 9-7 Implement a custom static method
  if (await Student.isUserExists(studentData.id)) {
    throw new Error('user already registerd');
  }
  const result = await Student.create(studentData);
  return result;
Enter fullscreen mode Exit fullscreen mode

9-8 Implement mongoose middleware part

npm i bcrypt
npm i -D @types/bcrypt
Enter fullscreen mode Exit fullscreen mode
BCRYPT_SALT_ROUND=12 //.env file
 bycrypt_salt_rounds: process.env.BCRYPT_SALT_ROUND, //.config file

Enter fullscreen mode Exit fullscreen mode
//post save middleware 
studentSchema.post('save', function (doc, next) {
  doc.password = '';
  // console.log('post hook: we save our data', this);
  next();
});

//query find middleware
studentSchema.pre('find', function (next) {
  // console.log('post hook: we save our data', this);
  this.find({ isDeleted: { $ne: true } });

  next();
});

//findOne
studentSchema.pre('findOne', function (next) {
  // console.log('post hook: we save our data', this);
  this.find({ isDeleted: { $ne: true } });

  next();
});

//aggregate
studentSchema.pre('aggregate', function (next) {
  // console.log('post hook: we save our data', this);
  this.pipeline().unshift({ $match: { isDeleted: { $ne: true } } });

  next();
});
Enter fullscreen mode Exit fullscreen mode
//Encrypt & pre save middleware/hook: will work on create on save function
studentSchema.pre('save', async function (next) {
  // console.log('pre hook: we save our data', this);

  //hashing password and save into DB
  // eslint-disable-next-line @typescript-eslint/no-this-alias
  const user = this; // documents
  user.password = await bcrypt.hash(
    user.password,
    Number(config.bycrypt_salt_rounds),
  );
  next();
});

Enter fullscreen mode Exit fullscreen mode

9-9 How to implement delete data in another way

//post save middleware 
studentSchema.post('save', function (doc, next) {
  doc.password = '';
  // console.log('post hook: we save our data', this);
  next();
});

Enter fullscreen mode Exit fullscreen mode

9-10 How to implement query middlewares

  this.find({ isDeleted: { $ne: true } });
Enter fullscreen mode Exit fullscreen mode
//aggregate
studentSchema.pre('aggregate', function (next) {
  // console.log('post hook: we save our data', this);
  this.pipeline().unshift({ $match: { isDeleted: { $ne: true } } });

  next();
});
Enter fullscreen mode Exit fullscreen mode
const getSignleStudentsFromBD = async (id: string) => {
  //aggregate system
  const result = await Student.aggregate([{ $match: { id: id } }]);
  return result;
};

Enter fullscreen mode Exit fullscreen mode

9-11 Mongoose Virtuals and Module Summary

const opts = { toJSON: { virtuals: true } };
const userSchema = mongoose.Schema({
  _id: Number,
  email: String
}, opts);
Enter fullscreen mode Exit fullscreen mode
  { toJSON: { virtuals: true } },
);

//virtual
studentSchema.virtual('FullName').get(function () {
  return `${this.name.firstName} ${this.name.middleName} ${this.name.lastName}`;
});

Enter fullscreen mode Exit fullscreen mode


Top comments (0)