乐闻世界logo
搜索文章和话题

How to integrate databases in NestJS?

2月17日 22:40

Database Integration Overview

NestJS provides comprehensive support for multiple databases, including relational databases (like MySQL, PostgreSQL) and non-relational databases (like MongoDB). By using ORM/ODM libraries such as TypeORM, Prisma, Mongoose, developers can easily implement database operations.

TypeORM Integration

Install Dependencies

bash
npm install @nestjs/typeorm typeorm npm install mysql2 # or pg, sqlite3, better-sqlite3, etc.

Configure TypeORM

typescript
import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { User } from './entities/user.entity'; @Module({ imports: [ TypeOrmModule.forRoot({ type: 'mysql', host: 'localhost', port: 3306, username: 'root', password: 'password', database: 'test', entities: [User], synchronize: true, // Should be false in production logging: true, }), TypeOrmModule.forFeature([User]), ], providers: [UserService], controllers: [UserController], }) export class UserModule {}

Create Entity

typescript
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm'; @Entity('users') export class User { @PrimaryGeneratedColumn() id: number; @Column({ unique: true }) email: string; @Column() password: string; @Column() name: string; @Column({ default: true }) isActive: boolean; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; }

Create Repository

typescript
import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { User } from './entities/user.entity'; import { CreateUserDto } from './dto/create-user.dto'; @Injectable() export class UserService { constructor( @InjectRepository(User) private userRepository: Repository<User>, ) {} async create(createUserDto: CreateUserDto): Promise<User> { const user = this.userRepository.create(createUserDto); return this.userRepository.save(user); } async findAll(): Promise<User[]> { return this.userRepository.find(); } async findOne(id: number): Promise<User> { return this.userRepository.findOne({ where: { id } }); } async update(id: number, updateUserDto: any): Promise<User> { await this.userRepository.update(id, updateUserDto); return this.findOne(id); } async remove(id: number): Promise<void> { await this.userRepository.delete(id); } async findByEmail(email: string): Promise<User> { return this.userRepository.findOne({ where: { email } }); } }

Prisma Integration

Install Dependencies

bash
npm install @prisma/client npm install prisma --save-dev npx prisma init

Configure Prisma

prisma
// prisma/schema.prisma datasource db { provider = "mysql" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } model User { id Int @id @default(autoincrement()) email String @unique password String name String isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt }

Create Prisma Service

typescript
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common'; import { PrismaClient } from '@prisma/client'; @Injectable() export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy { async onModuleInit() { await this.$connect(); } async onModuleDestroy() { await this.$disconnect(); } }

Use Prisma

typescript
import { Injectable } from '@nestjs/common'; import { PrismaService } from './prisma.service'; import { CreateUserDto } from './dto/create-user.dto'; @Injectable() export class UserService { constructor(private prisma: PrismaService) {} async create(createUserDto: CreateUserDto) { return this.prisma.user.create({ data: createUserDto, }); } async findAll() { return this.prisma.user.findMany(); } async findOne(id: number) { return this.prisma.user.findUnique({ where: { id }, }); } async update(id: number, updateUserDto: any) { return this.prisma.user.update({ where: { id }, data: updateUserDto, }); } async remove(id: number) { return this.prisma.user.delete({ where: { id }, }); } }

Mongoose Integration

Install Dependencies

bash
npm install @nestjs/mongoose mongoose

Configure Mongoose

typescript
import { Module } from '@nestjs/common'; import { MongooseModule } from '@nestjs/mongoose'; import { User, UserSchema } from './schemas/user.schema'; import { UserService } from './user.service'; import { UserController } from './user.controller'; @Module({ imports: [ MongooseModule.forRoot('mongodb://localhost:27017/nest'), MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]), ], providers: [UserService], controllers: [UserController], }) export class UserModule {}

Create Schema

typescript
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { Document } from 'mongoose'; @Schema() export class User extends Document { @Prop({ required: true, unique: true }) email: string; @Prop({ required: true }) password: string; @Prop({ required: true }) name: string; @Prop({ default: true }) isActive: boolean; @Prop({ default: Date.now }) createdAt: Date; @Prop({ default: Date.now }) updatedAt: Date; } export const UserSchema = SchemaFactory.createForClass(User);

Create Mongoose Service

typescript
import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { User } from './schemas/user.schema'; import { CreateUserDto } from './dto/create-user.dto'; @Injectable() export class UserService { constructor( @InjectModel(User.name) private userModel: Model<User>, ) {} async create(createUserDto: CreateUserDto): Promise<User> { const createdUser = new this.userModel(createUserDto); return createdUser.save(); } async findAll(): Promise<User[]> { return this.userModel.find().exec(); } async findOne(id: string): Promise<User> { return this.userModel.findOne({ _id: id }).exec(); } async update(id: string, updateUserDto: any): Promise<User> { return this.userModel.findByIdAndUpdate(id, updateUserDto, { new: true }).exec(); } async remove(id: string): Promise<User> { return this.userModel.findByIdAndDelete(id).exec(); } }

Database Migrations

TypeORM Migrations

bash
# Generate migration npm run typeorm migration:generate -- -n CreateUserMigration # Run migration npm run typeorm migration:run # Revert migration npm run typeorm migration:revert

Prisma Migrations

bash
# Create migration npx prisma migrate dev --name init # Apply migration npx prisma migrate deploy # Reset database npx prisma migrate reset

Transaction Handling

TypeORM Transactions

typescript
import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, DataSource } from 'typeorm'; import { User } from './entities/user.entity'; import { Order } from './entities/order.entity'; @Injectable() export class OrderService { constructor( private dataSource: DataSource, @InjectRepository(User) private userRepository: Repository<User>, @InjectRepository(Order) private orderRepository: Repository<Order>, ) {} async createOrderWithUser(userId: number, orderData: any) { const queryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); await queryRunner.startTransaction(); try { const user = await queryRunner.manager.findOne(User, { where: { id: userId } }); const order = queryRunner.manager.create(Order, { ...orderData, user, }); await queryRunner.manager.save(order); await queryRunner.commitTransaction(); return order; } catch (err) { await queryRunner.rollbackTransaction(); throw err; } finally { await queryRunner.release(); } } }

Prisma Transactions

typescript
async createOrderWithUser(userId: number, orderData: any) { return this.prisma.$transaction(async (prisma) => { const user = await prisma.user.findUnique({ where: { id: userId }, }); const order = await prisma.order.create({ data: { ...orderData, user: { connect: { id: userId }, }, }, }); return order; }); }

Relationship Mapping

TypeORM Relationships

typescript
@Entity('users') export class User { @PrimaryGeneratedColumn() id: number; @Column() name: string; @OneToMany(() => Order, order => order.user) orders: Order[]; } @Entity('orders') export class Order { @PrimaryGeneratedColumn() id: number; @Column() userId: number; @ManyToOne(() => User, user => user.orders) user: User; @Column() product: string; }

Prisma Relationships

prisma
model User { id Int @id @default(autoincrement()) name String orders Order[] } model Order { id Int @id @default(autoincrement()) userId Int user User @relation(fields: [userId], references: [id]) product String }

Database Connection Pool Configuration

TypeORM Connection Pool

typescript
TypeOrmModule.forRoot({ type: 'mysql', host: 'localhost', port: 3306, username: 'root', password: 'password', database: 'test', entities: [__dirname + '/**/*.entity{.ts,.js}'], synchronize: false, extra: { connectionLimit: 10, }, })

Prisma Connection Pool

prisma
datasource db { provider = "mysql" url = env("DATABASE_URL") // Connection pool configuration connection_limit = 10 }

Best Practices

  1. Use DTOs: Use data transfer objects to validate and transform data
  2. Environment Variables: Use environment variables to manage database configuration
  3. Migration Management: Use migrations to manage database schema changes
  4. Transaction Handling: Use transactions when atomic operations are needed
  5. Index Optimization: Add indexes for frequently queried fields
  6. Connection Pooling: Configure connection pool size appropriately
  7. Soft Delete: Implement soft delete instead of physical delete
  8. Query Optimization: Avoid N+1 query problems

Summary

NestJS database integration provides:

  • Support for multiple databases
  • Flexible ORM/ODM choices
  • Complete type safety
  • Powerful relationship mapping
  • Convenient transaction handling

Mastering database integration is the foundation for building data-driven NestJS applications. By properly selecting and using ORM/ODM and following best practices, you can build high-performance, maintainable data access layers.

标签:NestJS