Open In App

How to make Mongo schema from pure Typescript classes ?

Improve
Improve
Like Article
Like
Save
Share
Report

TypeScript is an object-oriented programming language, and it is a superset of JavaScript and contains all of its elements. By using TSC (TypeScript Compiler), we can convert Typescript code (.ts file) to JavaScript (.js file). It is open-source and its code is easier to read and understand. 

MongoDB is a versatile widely used NoSQL documentation based database. A collection can hold a bunch of documents. We can assume a collection as a table in RDBMS technology, but no strong entity relationships are required in the collection. A mongoose schema is equivalent to a collection. We can keep different data inside a Mongoose schema to create the collection in MongoDB. In this article, let us see how to make Mongo schema from pure Typescript class. The extension of the Typescript file is .ts and usually, from Angular framework projects, we are using Typescript classes, and let us see in detail. In order to interact with MongoDB, we require Mongoose. 

Project Setup and Module Installation:

Step 1: We are going to use the Typescript class, let us create by initializing a project using the following command.

 yarn init (or npm init ) 

 

When prompted, set the entry point to the following file.

src/server.ts .

Step 2: Install the required module using the following command.

# Dependency to connect to create MongoDB 
# Schema and connect to mongodb
yarn add express mongoose

# Dependency to create TypeScript files, 
# Dependency to execute those files in Node
# Dependency to speed up the development
yarn add -D nodemon typescript ts-node 
    @types/express @types/mongoose @types/node

# GlobalDependencies
npm i -g typescript ts-node

package.json: Our package.json file will look like this.

{
  "name": "mongo-typescript",
  "version": "1.0.0",
  "main": "src/server.ts",
  "license": "MIT",
  "scripts": {
    "start": "node --inspect=5858 -r ts-node/register ./src/server.ts",
    "dev": "nodemon",
    "build": "tsc",
    "script": "cd src/scripts && ts-node"
  },
  "dependencies": {
    "express": "^4.17.1",
    "mongoose": "^5.9.7"
  },
  "devDependencies": {
    "@types/express": "^4.17.6",
    "@types/mongoose": "^5.7.10",
    "@types/node": "^13.11.1",
    "nodemon": "^2.0.3",
    "ts-node": "^8.8.2",
    "typescript": "^3.8.3"
  }
}

tsconfig.json: This file has to be created in the root directory, and it will tell the compiler about the location for TypeScript files, and it will allow us to use ES6 import/export syntax.

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "outDir": "dist",
    "sourceMap": true
  },
  "include": ["src/**/*.ts"],
  "exclude": ["node_modules", ".vscode"]
}

Connecting to the Database: For database connectivity, Create a separate folder using the following commands.

mkdir src 
cd src 
mkdir database 
touch database.ts

Project Structure: It will look like this.

 

Example:

database.ts




import * as Mongoose from 'mongoose';
import { EmployeeModel } from './employees/employees.model';
  
let database: Mongoose.Connection;
  
export const connect = () => {
    // Add your own uri below, here my dbname is UserDB
    // and we are using the local mongodb
    const uri =
  
    if (database) {
        return;
    }
    // In order to fix all the deprecation warnings, 
    // below are needed while connecting
    Mongoose.connect(uri, {
        useNewUrlParser: true,
        useFindAndModify: true,
        useUnifiedTopology: true,
        useCreateIndex: true,
    });
  
    database = Mongoose.connection;
    // When mentioned database is available and successfully connects
    database.once('open', async () => {
        console.log('Connected to database successfully');
    });
  
    // In case of any error
    database.on('error', () => {
        console.log(`Error connecting to database. Check Whether mongoDB
        installed or you can try to give opensource Mongo Atlas database`);
    });
  
    return {
        EmployeeModel
    };
};
  
// Safer way to get disconnected
export const disconnect = () => {
    if (!database) {
        return;
    }
  
    Mongoose.disconnect();
};


server.ts




import * as express from "express";
import { connect } from "./database/database";
  
const app = express();
  
// Available port number and it should not 
// be used by other services
const port = 5002;
  
connect();
  
// To indicate the project initiated, 
// let us add console message
app.listen(port, () => {
    console.log(`Server started on http://localhost:${port}`);
});


Create models

Typescript files are helpful to create Mongo Schema. It is mentioned as Three parts to a Mongoose model (schema, static methods, and instance methods), Fourth one is to hold our TypeScript interfaces, and the fifth to bring everything together.

Inside the src/database/<collectionname> folder, let us create the models. Here <<collectionname> represents the name of MongoDB collection. Let us have it as employees.

  • <collectionname>.schema.ts: Define the Mongoose Schema, which helps for the determination of the shape of our MongoDB documents.
  • <collectionname>.statics.ts: Required static methods are added and called on the model itself.
  • <collectionname>.methods.ts: Instance methods of our model, functions which can be called on individual model instances.
  • <collectionname>.types.ts: Store the types we’ll use in the other files.
  • <collectionname>.model.ts: It is used to combine everything together.

We can use the following command to create a directory and files.

# Move to scr folder and create database folder
cd src 
mkdir database 

# Move to database folder and create employees folder
cd database 
mkdir employees

# Move to employees folder and create files
cd employees 
touch employees.schema.ts employees.statics.ts 
touch employees.methods.ts employees.types.ts employees.model.ts

employees.schema.ts




// Main schema file where we can define the
// required attributes
import * as Mongoose from "mongoose";
  
const EmployeeSchema = new Mongoose.Schema({
    firstName: String,
    lastName: String,
    age: Number,
    dateOfJoining: {
        type: Date,
        default: new Date(),
    },
    lastUpdated: {
        type: Date,
        default: new Date(),
    },
    gender: String,
    department: String,
  
    // All other required attributes
    // should be given here
});
  
export default EmployeeSchema;


  • IEmployeeDocument: Inclusion of our fields and other elements of a standard Mongoose Document.
  • IEmployeeModel: Representation of a standard Mongoose Model, containing documents of our IEmployeeDocument type.

employees.types.ts




import { Document, Model } from "mongoose";
  
// These fields represent fields of collection 
// and name of the collection is Employee
export interface IEmployee {
    firstName: string;
    lastName: string;
    age: number;
    dateOfEntry?: Date;
    lastUpdated?: Date;
    gender: String;
    department: String;
}
  
export interface IEmployeeDocument extends IEmployee, Document { }
export interface IEmployeeModel extends Model<IEmployeeDocument> { }


 

employees.model.ts




import { model } from "mongoose";
import { IEmployeeDocument } from "./employees.types";
import EmployeeSchema from "./employees.schema";
  
export const EmployeeModel = model<IEmployeeDocument>("employee",
  EmployeeSchema
)


Create two static methods as shown below:

  • findOneOrCreate: Checks for an entry for its existence and if not, creates a new entry.
  • findByAge: Returns an array of employees, based on a provided age range.

Similarly, we can define methods depends upon the requirement like findByGender, findByDepartment, etc., which ultimately matches our requirements

employees.statics.ts




import { IEmployeeDocument, IEmployeeModel } from "./employees.types";
  
// Check for the existence of an entry 
// and if it is not available, create one
export async function findOneOrCreate(
    this: IEmployeeModel,
    {
        firstName,
        lastName,
        age,
        gender,
        department,
    }: {
        firstName: string; lastName: string; age: number;
        gender: string; department: string
    }
): Promise<IEmployeeDocument> {
    const employeeRecord = await this.findOne({
        firstName,
        lastName, age, gender, department
    });
    if (employeeRecord) {
        return employeeRecord;
    } else {
        return this.create({
            firstName, lastName,
            age, gender, department
        });
    }
}
  
export async function findByAge(
    this: IEmployeeModel,
    min?: number,
    max?: number
): Promise<IEmployeeDocument[]> {
    return this.find({ age: { $gte: min || 0, $lte: max || Infinity } });
}
  
// Similarly add the rest of the methods according to the requirement


employees.methods.ts




import { Document } from "mongoose";
import { IEmployeeDocument } from "./employees.types";
  
export async function setLastUpdated(
  this: IEmployeeDocument): Promise<void> {
    const now = new Date();
    if (!this.lastUpdated || this.lastUpdated < now) {
        this.lastUpdated = now;
        await this.save();
    }
}
  
export async function sameLastName(
    this: IEmployeeDocument): Promise<Document[]> {
        return this.model("employee")
            .find({ lastName: this.lastName });
}


employees.schema.ts




import * as Mongoose from "mongoose";
import { findOneOrCreate, findByAge } from "./employees.statics";
import { setLastUpdated, sameLastName } from "./employees.methods";
  
const EmployeeSchema = new Mongoose.Schema({
    firstName: String,
    lastName: String,
    age: Number,
    dateOfJoining: {
        type: Date,
        default: new Date(),
    },
    lastUpdated: {
        type: Date,
        default: new Date(),
    },
    gender: String,
    department: String,
    // All other required attributes should be given here
});
  
EmployeeSchema.statics.findOneOrCreate = findOneOrCreate;
EmployeeSchema.statics.findByAge = findByAge;
  
EmployeeSchema.methods.setLastUpdated = setLastUpdated;
EmployeeSchema.methods.sameLastName = sameLastName;
  
export default EmployeeSchema;


employees.types.ts




import { Document, Model } from "mongoose";
  
export interface IEmployee {
    firstName: string;
    lastName: string;
    age: number;
    dateOfJoining?: Date;
    lastUpdated?: Date;
    gender: String;
    department: String;
}
  
export interface IEmployeeDocument extends IEmployee, Document {
    setLastUpdated: (this: IEmployeeDocument) => Promise<void>;
    sameLastName: (this: IEmployeeDocument) => Promise<Document[]>;
}
  
export interface IEmployeeModel extends Model<IEmployeeDocument> {
    findOneOrCreate: (
        this: IEmployeeModel,
        {
            firstName,
            lastName,
            age,
            gender,
            department,
        }: { firstName: string; lastName: string; age: number; 
            gender: string; department: string; }
    ) => Promise<IEmployeeDocument>;
    findByAge: (
        this: IEmployeeModel,
        min?: number,
        max?: number
    ) => Promise<IEmployeeDocument[]>;
}


sampleEmployeeData.ts




import { EmployeeModel } from "../database/employees/employees.model";
import { connect, disconnect } from "../database/database";
  
(async () => {
    connect();
    // Via "sampleEmployeeData.ts" we can add data to Mongoose schema
    // Our schema name is employees
    const employees = [
        {
            firstName: "Rachel", lastName: "Green", age: 25,
            gender: "Female", department: "Design"
        },
        {
            firstName: "Monica", lastName: "Geller", age: 25,
            gender: "Female", department: "Catering"
        },
        {
            firstName: "Phebe", lastName: "Phebe", age: 25,
            gender: "Female", department: "Masus"
        },
        {
            firstName: "Ross", lastName: "Geller", age: 30,
            gender: "Male", department: "Paleontology"
        },
        {
            firstName: "Chandler", lastName: "Bing", age: 30,
            gender: "Male", department: "IT"
        },
        {
            firstName: "Joey", lastName: "Joey", age: 30,
            gender: "Male", department: "Dramatist"
        },
    ];
  
    try {
        for (const employee of employees) {
            await EmployeeModel.create(employee);
            console.log(`Created employee ${employee.firstName} 
            ${employee.lastName}`);
        }
  
        disconnect();
    } catch (e) {
        console.log(e);
    }
})();


Steps to run the application: Start the server using the following command.

yarn start

The next step is we need to create the collections using the Mongoose schema. Use the following command to fill in the data:

yarn script sampleEmployeeData.ts

Output:

In the Mongo shell, we can verify the same. In UserDB database, on querying db.employees.find().pretty(), we can see the output:

Conclusion: Typescript files are so cool which has advanced features of JavaScript and by using mongoose, Express we can easily create MongoDB schemas by using Typescript files



Last Updated : 08 Sep, 2022
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads