NestJS 3 分钟搭好 MySQL + MongoDB,CRUD 复制粘贴直接运行

基于上一篇内容《为什么现代 Node 后端都选 NestJS + TypeScript?这组合真香了》,这篇文章继续写数据库的连接。

所以今天把MySQL、MongoDB全接上,做个小实例。朋友们项目里用什么数据库可以视情况而定。 这里的功能分别为:

  • MySQL:存用户
  • MongoDB:存日志

代码短、跟着敲就行。

1. 生成对应架构

执行以下命令生成相关模块代码(Module/Service/Controller)

bash 复制代码
nest g res user
nest g res log

2. 装包

bash 复制代码
pnpm i @nestjs/typeorm typeorm mysql2
pnpm i @nestjs/mongoose mongoose

3. 连库

app.module.ts 一次配好

ts 复制代码
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { MongooseModule } from '@nestjs/mongoose';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TodoModule } from './todo/todo.module';
import { UserModule } from './user/user.module';
import { LogModule } from './log/log.module';

@Module({
  imports: [
    // MySQL
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'SV^u8@rB8',
      database: 'demo',
      autoLoadEntities: true,
      synchronize: true, // 仅本地用,生产关掉
    }),

    // MongoDB
    MongooseModule.forRoot('mongodb://localhost:27017/test'),

    // 业务模块
    TodoModule,

    UserModule,

    LogModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

代码生成了,接下来我们来处理数据库和增删改查的代码。

Mysql

1. 实体和数据表

数据库表

sql 复制代码
CREATE TABLE `user` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '用户名',
  `age` int DEFAULT NULL COMMENT '年龄',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户表';

MySQL 实体

ts 复制代码
// user.entity.ts
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn() id: number;
  @Column() name: string;
  @Column() age: number;
}

Dto

ts 复制代码
// create-user.dto.ts
export class CreateUserDto {
  name: string;
  age: number;
}

这里容易出现一个Eslint问题的爆红,如下图:

出现这种情况执行以下命令:

bash 复制代码
npx eslint "src/**/*.{ts,js}" --fix --ext .ts,.js

如果还是不行,再执行下这个

bash 复制代码
npx prettier --write "src/**/*.{ts,js,json}"

2. 业务代码(cv即可)

user.controller.ts

ts 复制代码
import { Controller, Get, Post, Body, Patch, Param, Delete,} from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Controller('user')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    return this.userService.create(createUserDto);
  }

  @Get()
  findAll() {
    return this.userService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.userService.findOne(+id);
  }

  @Patch(':id')
  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
    return this.userService.update(+id, updateUserDto);
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.userService.remove(+id);
  }
}

user.module.ts

这里稍微的修改了一下,引入了TypeOrmModule

ts 复制代码
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { User } from './entities/user.entity';

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  controllers: [UserController],
  providers: [UserService],
})
export class UserModule {}

user.service.ts

完成了增删改查的业务代码

ts 复制代码
import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { User } from './entities/user.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private readonly repo: Repository<User>,
  ) {}

  async create(createUserDto: CreateUserDto): Promise<User> {
    return await this.repo.save(createUserDto);
  }

  async findAll(): Promise<User[]> {
    return await this.repo.find();
  }

  async findOne(id: number): Promise<User> {
    const user = await this.repo.findOne({ where: { id } });
    if (!user) {
      throw new Error(`User with ID ${id} not found`);
    }
    return user;
  }

  async update(id: number, updateUserDto: UpdateUserDto): Promise<User> {
    const user = await this.findOne(id);
    Object.assign(user, updateUserDto);
    return await this.repo.save(user);
  }

  async remove(id: number): Promise<void> {
    const user = await this.findOne(id);
    await this.repo.remove(user);
  }
}

3. 跑起来,测试下接口

bash 复制代码
npm run start

新增

POST http://localhost:3000/user

json 复制代码
{ "name": "张三", "age": 30 }

修改

POST http://localhost:3000/user

json 复制代码
{ "id": 1, "name": "张三", "age": 31 }

删除

DELETE http://localhost:3000/user/1

查询

GET http://localhost:3000/user/1

这里实现mysql的增删改查就完成了

MongoDB

大致流程和mysql是一样的,写法稍微有些差别

1. 实体和集合

创建一个集合

sql 复制代码
db.createCollection("logs");

集合 实体

ts 复制代码
// log.entity.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document, Types } from 'mongoose';

export type LogDocument = Log & Document;

@Schema()
export class Log {
  _id?: Types.ObjectId;

  @Prop({ required: true })
  message: string;

  @Prop({ default: Date.now })
  timestamp: Date;
}

export const LogSchema = SchemaFactory.createForClass(Log);

Dto

ts 复制代码
// create-log.dto.ts
export class CreateLogDto {
  message: string;
  timestamp?: Date;
}

2. 业务代码(cv即可)

log.controller.ts

ts 复制代码
import {Controller, Get, Post, Body, Patch, Param, Delete} from '@nestjs/common';
import { LogService } from './log.service';
import { CreateLogDto } from './dto/create-log.dto';
import { UpdateLogDto } from './dto/update-log.dto';

@Controller('log')
export class LogController {
  constructor(private readonly logService: LogService) {}

  @Post()
  create(@Body() createLogDto: CreateLogDto) {
    return this.logService.create(createLogDto);
  }

  @Get()
  findAll() {
    return this.logService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.logService.findOne(id);
  }

  @Patch(':id')
  update(@Param('id') id: string, @Body() updateLogDto: UpdateLogDto) {
    return this.logService.update(id, updateLogDto);
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.logService.remove(id);
  }
}

log.module.ts

引入了MongooseModule

ts 复制代码
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { LogService } from './log.service';
import { LogController } from './log.controller';
import { Log, LogSchema } from './entities/log.entity';

@Module({
  imports: [MongooseModule.forFeature([{ name: Log.name, schema: LogSchema }])],
  controllers: [LogController],
  providers: [LogService],
})
export class LogModule {}

user.service.ts

增删改查的业务代码

ts 复制代码
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { CreateLogDto } from './dto/create-log.dto';
import { UpdateLogDto } from './dto/update-log.dto';
import { Log, LogDocument } from './entities/log.entity';

@Injectable()
export class LogService {
  constructor(@InjectModel(Log.name) private logModel: Model<LogDocument>) {}

  async create(createLogDto: CreateLogDto): Promise<Log> {
    const createdLog = new this.logModel(createLogDto);
    return createdLog.save();
  }

  async findAll(): Promise<Log[]> {
    return this.logModel.find().exec();
  }

  async findOne(id: string): Promise<Log> {
    const log = await this.logModel.findById(id).exec();
    if (!log) {
      throw new Error(`Log with ID ${id} not found`);
    }
    return log;
  }

  async update(id: string, updateLogDto: UpdateLogDto): Promise<Log> {
    const updatedLog = await this.logModel
      .findByIdAndUpdate(id, updateLogDto, { new: true })
      .exec();
    if (!updatedLog) {
      throw new Error(`Log with ID ${id} not found`);
    }
    return updatedLog;
  }

  async remove(id: string): Promise<void> {
    const result = await this.logModel.findByIdAndDelete(id).exec();
    if (!result) {
      throw new Error(`Log with ID ${id} not found`);
    }
  }
}

3. 启动,测试接口

bash 复制代码
npm run start

新增

POST http://localhost:3000/log

json 复制代码
{ "message": "张三的消息" }

修改

POST http://localhost:3000/log

json 复制代码
{ "id": 1, "message": "李四的消息"}

删除

DELETE http://localhost:3000/log/1

查询

GET http://localhost:3000/log/1

MongoDB的增删改查完成

小结

  • MySQL:使用TypeORM实体一把梭
  • MongoDB:使用Schema装饰器直接上

NestJS真的是结构清晰,开发很快,再也不用从头造轮子了。

我是大华,专注分享前后端开发的实战笔记。关注我,少走弯路,一起进步!

📌往期精彩

《Elasticsearch 太重?来看看这个轻量级的替代品 Manticore Search》

《别再if套if了!Java中return的9种优雅写法》

《别学23种了!Java项目中最常用的6个设计模式,附案例》

《写给小公司前端的 UI 规范:别让页面丑得自己都看不下去》

《Vue3+TS设计模式:5个真实场景让你代码更优雅》

相关推荐
kevinlaizhiyu16 小时前
Object.defineProperty详解:从基础到实战的完整指南
javascript
小高00716 小时前
🎯v-for 先还是 v-if 先?Vue2/3 编译真相
前端·javascript·vue.js
zzywxc78716 小时前
如何利用AI IDE快速构建一个简易留言板系统
开发语言·前端·javascript·ide·vue.js·人工智能·前端框架
linyi716 小时前
Rocket.Chat Video Call
前端·javascript
鹏多多16 小时前
开发个人微信小程序类目选择/盈利方式/成本控制与服务器接入指南
前端·javascript·程序员
掘金安东尼16 小时前
前端周刊第429期(2025年8月25日–8月31日)
前端·javascript·面试
Moment17 小时前
该用 <img> 还是 new Image()?前端图片加载的决策指南 😌😌😌
前端·javascript·面试
江城开朗的豌豆17 小时前
为什么在render里调setState,代码会和你“翻脸”?
前端·javascript·react.js
江城开朗的豌豆17 小时前
子组件改状态,父组件会“炸毛”吗?
前端·javascript·react.js