- Home
- >
- Software Development
- >
- TypeORM With NEST JS – Basic Tutorial
In this article, we will be using TypeORM with Nest Js to integrate database with our application. But before starting with TypeORM, let’s have a brief look over the concept of Object-relational mapping(ORM).
Object-relational mapping as a technique for converting data between incompatible type systems using object-oriented programming languages. In other words, ORM is a programming technique in which a metadata descriptor is used to connect object code to a relational database.
Source Wikipedia
Object code is written in object-oriented programming (OOP) languages such as C++, JAVA, etc. We will be using TypeScript for creations of our object-oriented programming.
In addition to the data access technique, ORM also provide
simplified development because it automates object-to-table and table-to-object conversion, resulting in lower development and maintenance costs.
Now, when we have a good idea about what is the notion of ORM is, let’s understand what TypeORM is :-
TypeORM: TypeORM is an ORM that can run in NodeJS, Browser, Cordova, PhoneGap, Ionic, React Native, NativeScript, Expo, and Electron platforms and can be used with TypeScript and JavaScript (ES5, ES6, ES7, ES8).
Topics:
- Creating a model( or Table ).
- Primary / Auto-generation column.
- Relationship between two or more models.
- Our Project.
Creating a model/ Table
The first step in the database is to create a table. With TypeORM, we create database tables through models. So models in our app will be our database tables.
Now create a sample model “Cat” for a better understanding.
export class Cat {
id: number;
name: string;
breed: string;
age: string;
}
Note: The database table is not created for each model but only for those models which are declared as entities. To declare a model as an entity, we just need to add ‘@Entity()‘ decorator before the declaration of the Class defining our model.
In addition to this, we should ideally have columns in our model now because the table which will be generated (because of the model being declared as an entity now) makes no sense without any column in it. To add a data member of a model as a column, we need to decorate a data member with a ‘@Column()‘ decorator.
Let us modify our above model of ‘Cats’ by adding ‘@Entity()’ and ‘@Column()’ decorator.
@Entity()
export class Cat {
@Column()
id: number;
@Column()
name: string;
@Column()
breed: string;
@Column()
age: string;
}
Primary / auto-generated primary column
For creating a column as a primary key of the database table, we need to use ‘@PrimaryColumn()‘ decorator instead of ‘@Column()‘ decorator. And for the primary column to be self-generated, we need to use ‘@PrimaryGeneratedColumn()‘ instead of ‘@PrimaryColumn()‘.
By making ‘id’ in ‘Cat’ as auto-generated primary key, our Cat model will look like this:
@Entity()
export class Cat {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
breed: string;
@Column()
age: string;
}
Relationship between two or more models
A relationship, in the context of databases, is a situation that exists between two relational database tables when one table has a foreign key that references the primary key of the other table. Relationships allow relational databases to split and store data in different tables while linking disparate data items.
There are 3 types of relationships in relational database design :-
- One-to-One (implemented by ‘@OneToOne()‘ decorator)
- One-to-Many / Many-to-One (implemented by ‘@OneToMany()‘ decorator )
- Many-to-Many (implemented by ‘@ManyToMany()‘ decorator)
Our Project
In this section, we will create a NestJS project in which we will have three tables/entities as follows:
- UserEntity
- BookEntity
- GenreEntity
Relationships between the entities:
- UserEntity and BookEntity: One-To-Many
- BookEntity and GenreEntity: Many-To-Many
In simple words, a user can have many books and each book can belong to more than one Genre.
For now, we will create the above-mentioned entities as follows without any relationship between them as follows:
MyProject/db/user.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, BaseEntity, OneToMany } from 'typeorm';
import BookEntity from './book.entity';
@Entity()
export default class UserEntity extends BaseEntity {
@PrimaryGeneratedColumn()
id: number;
@Column({ length: 500 })
name: string;
}
MyProject/db/book.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, BaseEntity, ManyToOne, ManyToMany, JoinTable } from 'typeorm';
import UserEntity from './user.entity';
import GenreEntity from './genre.entity';
@Entity()
export default class BookEntity extends BaseEntity
{
@PrimaryGeneratedColumn()
id: number;
@Column({ length: 500 })
name: string;
}
MyProject/db/genre.entity.ts
@Entity()
export default class GenreEntity extends BaseEntity {
@PrimaryGeneratedColumn()
id: number;
@Column()
type: string;
}
For setting up the relation between UserEntity and BookEntity, we have to add the following code in UserEntity and BookEntity Class as follows:
MyProject/db/user.entity.ts
// 1:n relation with bookEntity
@OneToMany( type => BookEntity , book => book.user)
books: BookEntity[];
type => BookEntity
is a function that returns the class of the entity with which we want to make our relationship.
book => book.user states which column to be used by ‘BookEntity’ to get the associated user.
Now, we have set a One-to-Many relationship from the ‘UserEntity’ side. As One-to-Many is complimentary with Many-to-One, we should state the ‘Many-to-One’ relationship from BookEntity to UserEntity.
MyProject/db/book.entity.ts
// n:1 relation with books
@ManyToOne(type => UserEntity, user => user.books)
user: UserEntity;
Similarly, to make a many-to-many relationship between BookEntity and GenreEntity, we have to add the following code:
// n:n relation with genre
@ManyToMany(type => GenreEntity)
@JoinTable()
genres: GenreEntity[];
Here, ‘@JoinTable()’ decorator states that in a many-to-many relationship in BookEntity and GenreEntity, the ownership lies in the BookEntity side.
Now we are done with almost everything related to database and TypeORM. The only thing that remains is to establish a connection with the database. For this purpose, we have to create an ‘ormconfig.json’ file and add the following JSON code in it.
MyProject/ormconfig.json
{
"type": "sqlite",
"database": "./database.sqlite",
"synchronize": "true",
"entities": [
"dist/db/entity/**/*.js"
],
"cli": {
"entitiesDir": "src/db/entity"
}
}
The first line in the above JSON object specifies that the database we are using is ‘SQLite’.
Now we have to create the NEST controllers and services to handle the requests.
Here are the three DataTransferObjects we will be using in the further code:
MyProject/User/dto/create-user.dto.ts
export default class CreateUserDto {
readonly name: string;
readonly books: number[] ;
}
MyProject/User/dto/create-book.dto.ts
export default class CreateBookDto {
readonly name: string;
readonly userID: number;
readonly genreIDs: number[];
}
MyProject/User/dto/create-genre.dto.ts
export default class CreateGenreDto {
readonly type: string;
}
Below are the Controllers and Services for Users, Books, and Genres which will be handling the requests.
Users
MyProject/User/user.controller.ts
import { Body, Controller, Get, ParseIntPipe, Post, Put } from '@nestjs/common';
import { UserServices } from './user.services';
import CreateUserDto from './dto/create-user.dto';
@Controller('users')
export class UserController {
constructor(private readonly usersServices: UserServices) {}
//'postUser()' will handle the creating of new User
@Post('post')
postUser( @Body() user: CreateUserDto) {
return this.usersServices.insert(user);
}
// 'getAll()' returns the list of all the existing users in the database
@Get()
getAll() {
return this.usersServices.getAllUsers();
}
//'getBooks()' return all the books which are associated with the user
// provided through 'userID' by the request
@Get('books')
getBooks( @Body('userID', ParseIntPipe) userID: number ) {
return this.usersServices.getBooksOfUser(userID);
}
}
Myproject/User/user.service.ts
import { Injectable } from '@nestjs/common';
import UserEntity from '../db/entity/user.entity';
import CreateUserDto from './dto/create-user.dto';
import BookEntity from '../db/entity/book.entity';
import {getConnection} from "typeorm";
@Injectable()
export class UserServices {
async insert(userDetails: CreateUserDto): Promise<UserEntity> {
const userEntity: UserEntity = UserEntity.create();
const {name } = userDetails;
userEntity.name = name;
await UserEntity.save(userEntity);
return userEntity;
}
async getAllUsers(): Promise<UserEntity[]> {
return await UserEntity.find();
}
async getBooksOfUser(userID: number): Promise<BookEntity[]> {
console.log(typeof(userID));
const user: UserEntity = await UserEntity.findOne({where: {id: userID}, relations: ['books']});
return user.books;
}
}
Myproject/User/user.module.ts
import { Module } from '@nestjs/common';
import { UserServices } from './user.services';
import { UserController } from './user.controller';
@Module({
imports: [],
controllers: [UserController],
providers: [UserServices],
})
export class UserModule {}
Genre
MyProject/Genre/genre.controller.ts
import { Body, Controller, Get, Post } from '@nestjs/common';
import GenreServices from './genre.services';
import CreateGenreDto from './dto/create-genre.dto';
@Controller('genre')
export default class GenreController {
constructor(private readonly genreServices: GenreServices) {}
@Post('post')
postGenre( @Body() genre: CreateGenreDto) {
return this.genreServices.insert(genre);
}
@Get()
getAll() {
return this.genreServices.getAllGenre();
}
}
MyProject/Genre/genre.services.ts
import { Injectable } from '@nestjs/common';
import CreateGenreDto from './dto/create-genre.dto';
import GenreEntity from '../db/entity/genre.entity';
@Injectable()
export default class GenreServices {
async insert(genreDetails: CreateGenreDto): Promise<GenreEntity> {
const genreEntity: GenreEntity = GenreEntity.create();
const {type} = genreDetails;
genreEntity.type = type;
await GenreEntity.save(genreEntity);
return genreEntity;
}
async getAllGenre(): Promise<GenreEntity[]> {
return await GenreEntity.find();
}
}
MyProject/Genre/genre.module.ts
import { Module } from '@nestjs/common';
import GenreServices from './genre.services';
import GenreController from './genre.controller';
@Module({
imports: [],
controllers: [GenreController],
providers: [GenreServices],
})
export default class GenreModule {}
Books
MyProject/Books/books.controller.ts
import BookEntity from '../db/entity/book.entity';
import CreateBookDto from './dto/create-book.dto';
import UserEntity from '../db/entity/user.entity';
import { createQueryBuilder, getConnection } from 'typeorm';
import GenreEntity from '../db/entity/genre.entity';
export class BooksService {
async insert(bookDetails: CreateBookDto): Promise<BookEntity> {
const { name , userID , genreIDs } = bookDetails;
const book = new BookEntity();
book.name = name;
book.user = await UserEntity.findOne(userID) ;
book.genres=[];
for ( let i = 0; i < genreIDs.length ; i++)
{
const genre = await GenreEntity.findOne(genreIDs[i]);
book.genres.push(genre);
}
await book.save();
return book;
}
async getAllBooks(): Promise<BookEntity[] > {
// const user: UserEntity = await UserEntity.findOne({where: {id: 2}, relations: ['books']});
return BookEntity.find();
}
MyProject/Books/books.module.ts
import { Module } from '@nestjs/common';
import { BooksService } from './books.service';
import BooksController from './books.controller';
@Module({
imports: [],
controllers: [BooksController],
providers: [BooksService],
})
export default class BooksModule {}
Now, finally, this is the time to integrate everything with ‘app.module.ts’
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './User/user.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import UserEntity from './db/entity/user.entity';
import BooksModule from './Books/books.module';
import GenreModule from './Genre/genre.module';
import BookEntity from './db/entity/book.entity';
import GenreEntity from './db/entity/genre.entity';
@Module({
imports: [UserModule ,
BooksModule,
GenreModule,
TypeOrmModule.forFeature(
[UserEntity, BookEntity , GenreEntity],
),
TypeOrmModule.forRoot(),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
List of Keywords users find our article on Google:
nestjs typeorm |
typeorm find order |
typeorm many to many |
typeorm |
nest js tutorial |
nestjs tutorial |
nestjs reviews |
nestjs typeorm insert |
typeorm base entity |
nestjs many to one |
typeorm one to many |
nestjs typeorm entity |
nest js book |
nest js typeorm |
typeorm one to one |
nest js tutorials |
nestjs/typeorm |
typeorm findone |
nest js orm |
typeorm onetoone |
typeorm create database |
Source: InApps.net
Let’s create the next big thing together!
Coming together is a beginning. Keeping together is progress. Working together is success.