Module 5: In-Depth Exploration of MongoDB Queries
5-0 Introduction of be a Mongoose Master
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
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}
}
] )
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
}
] )
6-3 $group , $sum , $push aggregation stage
//group
db.test.aggregate( [
//stage-1
{$group:{_id:"$gender"}}
] )
//count sum
db.test.aggregate([
//stage-1
{ $group: { _id: "$address.country", count: {$sum: 1 }} }
])
//use push
db.test.aggregate([
//stage-1
{ $group: { _id: "$address.country", count: {$sum: 1 }, showMeName:{$push:"$name"}} }
])
//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,
}
}
])
6-4 explore more about $group & $project
//total salary
db.test.aggregate([
//stage-1
{
$group: {
_id: null,
totalSalary : {$sum: "$salary"}
}
},
])
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
}
}
])
6-5 Explore $group with $unwind aggregation stage
db.test.aggregate([
//stage-1
{
$unwind: "$interests"
},
//stage-2
{
$group: { _id: "$age", interestperage:{$push:"$interests"}}
}
])
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}
}
])
6-7 $facet, multiple pipeline aggregation stage
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 } }
}
]
}
}
])
6-8 $lookup stage, embedding vs referencing
db.orders.aggregate( [
{
$lookup:
{
from: "test",
localField: "userId",
foreignField: "_id",
as: "user"
}
}
] )
6-9 What is indexing, COLLSCAN vs IXSCAN
6-10 Explore compound index and text index
db.getCollection("massive-data").createIndex({ age: 1 })
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)
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);
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!');
});
});
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);
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
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}`)
});
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
"rootDir": "./src/",
"outDir": "./dist/",
tsc -w
"start-dev" : "nodemon ./dist/app/server.js",
rakib@pop-os:~/Documents/project-1/dist/app$ yarn start-dev
//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;
//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();
7-7 What is parsers, request and response object
tsc
import express, {Request, Response} from 'express';
app.get('/', (req: Request, res:Response) => {
yarn add -D nodemon
"start-dev": "nodemon ./dist/app/server.js",
//perser
app.use(express.json());
app.use(express.text());
app.post('/', (req: Request, res:Response) => {
console.log(req.body);
res.json({
message: "suffesfully done"
})
})
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;
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;
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);
})
// 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",
});
}
});
app.all('*', (req: Request, res: Response) => {
res.status(400).json({
success: false,
message: 'Route is not found',
});
});
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",
});
}
});
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
8-2 Installing express , mongoose, typescript, dotenv ,cors
npm init -y
- express
- mongose
- typescript
- cors
- 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
//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.
//then do this for create dist file for js
npm run build
//then run js code
node ./dist/app.js
//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
}
//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
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
//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
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)
}
}
//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;
//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
You’ll find that some files don’t 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",
//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
// 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"
}
npm run lint
8-4 Install prettierts-node-dev,fix formatting issues
*### Integrating Prettier *
Run the following command in the terminal:
npm install --save-dev prettier
// now a create a file of this=> .prettierrc.json
{
"semi": true,
"singleQuote": true
}
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
// package.json
{
// ...
"scripts": {
// ...others code..
"prettier": "prettier --ignore-path .gitignore --write \"./src/**/*.+(js|ts|json)\"",
},
// ...
}
//to run prettier
npm run prettier
// settings.json =>tthis is vscode setting then paste
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
...
}
=>install direct extesnion app
*Avoiding conflicts when working with ESLint and Prettier
*
npm install --save-dev eslint-config-prettier
// .eslintrc
{
// HERE and relace with previous estends
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
}
"scripts": {
"prettier": "prettier --ignore-path .gitignore --write \"./src/**/*.+(js|ts|json)\"",
"prettier:fix": "npx prettier --write src",
},
npm run prettier:fix
npm run build
// 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
//in package.json
"scripts": {
"start:prod": "node ./dist/server.js",
"start:dev": "ts-node-dev --respawn --transpile-only src/server.ts",
"build": "tsc",
// .env file for developemnt
NODE_ENV= development
PORT=5000
DATABASE_URL= mongodb+srv://admin:admin@cluster0.rp8qrq9.mongodb.net/?retryWrites=true&w=majority
8-5 Software design pattern , mvc vs modular, create an interface
=> go to this site: https://mongoosejs.com/docs/typescript.html
8-8 Create route , service and controller
Advanced CRUD with express, mongoose and typescript
9-1 Introduction to validation
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';
import validator from 'validator';
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',
},
validate: {
validator: (value: string) => validator.isEmail(value),
message: '{VALUE} is not valid',
},
Joi
npm i joi
import Joi from 'joi';
if (error) {
res.status(500).json({
success: false,
message: 'joi validation went wrong',
data: error.details,
});
}
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,
});
}
9-5 How to validate using zod
npm install zod
const { student: studentData } = req.body;
//------------------------------
// //==> data validation using zod=> IMPORTANT
const zodvalidatedData = studentValidationSchema.parse(studentData);
const result = await StudentServices.createStudentIntoDB(zodvalidatedData);
//-------------------------------
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;
};
export type StudentMethods = {
isUserExits(id: string): Promise<Student>;
};
export type StudentModel = Model<
Student,
Record<string, never>,
StudentMethods
>;
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>;
}
const studentSchema = new Schema<TStudent, StudentModel>(
// create cusitom static method
studentSchema.statics.isUserExists = async function (id: string) {
const existingUser = await Student.findOne({ id });
return existingUser;
};
// 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;
9-8 Implement mongoose middleware part
npm i bcrypt
npm i -D @types/bcrypt
BCRYPT_SALT_ROUND=12 //.env file
bycrypt_salt_rounds: process.env.BCRYPT_SALT_ROUND, //.config file
//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();
});
//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();
});
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();
});
9-10 How to implement query middlewares
this.find({ isDeleted: { $ne: true } });
//aggregate
studentSchema.pre('aggregate', function (next) {
// console.log('post hook: we save our data', this);
this.pipeline().unshift({ $match: { isDeleted: { $ne: true } } });
next();
});
const getSignleStudentsFromBD = async (id: string) => {
//aggregate system
const result = await Student.aggregate([{ $match: { id: id } }]);
return result;
};
9-11 Mongoose Virtuals and Module Summary
const opts = { toJSON: { virtuals: true } };
const userSchema = mongoose.Schema({
_id: Number,
email: String
}, opts);
{ toJSON: { virtuals: true } },
);
//virtual
studentSchema.virtual('FullName').get(function () {
return `${this.name.firstName} ${this.name.middleName} ${this.name.lastName}`;
});
Top comments (0)