NestJS+MongoDB高效CRUD接口开发全景指南

背景痛点

在上一篇文章中,我们通过 NestJS+WebSocket 实现了骰子游戏的毫秒级状态同步,但遗留了一个致命问题:

「当服务器重启时,所有房间状态瞬间蒸发!」

  • 房主开盅瞬间断电 → 本局游戏数据全丢失
  • 突发流量导致服务崩溃 → 玩家被迫回到初始页面
  • 运维更新版本 → 在线用户集体掉线且无法恢复

这暴露了纯内存方案的脆弱性------实时通信必须与持久化存储双剑合璧,才能真正支撑线上业务。

技术演进图

lua 复制代码
         [ 旧方案 ]                 ➜              [ 新架构 ]
  +---------------------+                        +---------------------+
  |   WebSocket服务      |                        |   WebSocket服务     |
  |  (内存存储房间状态)   |                        |  (状态实时同步)      |
  +----------+----------+                        +----------+----------+
             |                                            |
             |                                            ▼
  +----------+----------+                        +---------------------+
  |      致命弱点        |                        |   MongoDB集群       |
  |  ➤ 服务重启=数据清零 |                        | ➤ 持久化房间快照    |
  |  ➤ 无法追溯历史对局  |                        | ➤ 崩溃自动恢复      |
  +---------------------+                        +---------------------+

所以我们要实现数据的持久化存储,这样就不会影响现有用户的一些数据的丢失

实现

还是老样子 通过脚手架新建一个 Nest 项目

shell 复制代码
nest new mongo-demo

安装对应依赖

shell 复制代码
npm i @nestjs/mongoose mongoose

需要在 app.module.ts 配置如下来连接 MongoDB

js 复制代码
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MongooseModule } from "@nestjs/mongoose";

@Module({
  imports: [
    MongooseModule.forRoot("mongodb://username:password@localhost:27017/databaseName"), // 主要是这里
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

千万要注意 forRoot 里的内容,就是需要 MongoDB 对应的 账号密码,域名及库名 ,否则运行会报错。

如果信息内容都填对了,却还是没连上,就是有可能你的 MongoDB 服务没开,又或者被防火墙拦了,需要开放对应的端口,默认是 '27017'

然后运行你的服务,若显示如下,说明连接成功了


在 NestJS 中,Schema(模式) 是用于定义数据模型结构和约束的核心工具,尤其在集成 MongoDB(通过 Mongoose 模块)时起到关键作用。 以用户为例 我们定义一下数据模型结构

js 复制代码
// user.schema.ts
import { HydratedDocument } from "mongoose";
import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose";

export type UserDocument = HydratedDocument<User>;

@Schema()
export class User {
  @Prop()
  _id: string;

  @Prop()
  username: string;

  @Prop()
  avatar_url: string;
}

export const UserSchema = SchemaFactory.createForClass(User);

再创建一个 Service 类,实现数据的增删查改操作

js 复制代码
// user.service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User, UserDocument } from './user.schema';

@Injectable()
export class UserService {
  constructor(@InjectModel(User.name) private userModel: Model<UserDocument>) {}

  async create(data: any): Promise<User> {
    return this.userModel.create(data);
  }

  async findAll(data: object = {}): Promise<User[]> {
    return this.userModel.find(data).exec();
  }

  async findOne(id: string): Promise<User> {
    return this.userModel.findById(id).exec();
  }

  async update(id: string, data: any): Promise<User> {
    return this.userModel
      .findByIdAndUpdate(id, data, { new: true })
      .exec();
  }

  async remove(id: string): Promise<User> {
    return this.userModel.findByIdAndDelete(id).exec();
  }
}

然后在 app.module.vue 添加对应 schemaservice,这样就可以在全局使用它们。

js 复制代码
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MongooseModule } from "@nestjs/mongoose";
import { User, UserSchema } from './module/user/user.schema';
import { UserService } from './module/user/user.service';

@Module({
  imports: [
    MongooseModule.forRoot("mongodb://dice:[email protected]:27017/dice"),
    MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]), // 新增
  ],
  controllers: [AppController],
  providers: [AppService, UserService], // 新增
})
export class AppModule {}

接下来 我们把对应的操作通过接口实现,那就是 controllerservice 的代码实现,一般情况下会创建对应的 module ,在里面写对应的 controllerservice,这里为了方便测试,我们直接在app的控制层和服务层写对应的代码。

js 复制代码
// app.controller
import { Body, Controller, Get, Post, Query, Delete } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get('getUsers')
  getUsers() {
    return this.appService.getUsers();
  }

  @Post('createUser')
  createUser(@Body() body) {
    return this.appService.createUser(body);
  }

  @Post('updateUser')
  updateUser(@Query('id') id, @Body() body) {
    return this.appService.updateUser(id, body);
  }
  
  @Delete('deleteUser')
  deleteUser(@Body('id') id) {
    return this.appService.deleteUser(id);
  }
}

控制层就是写对应的接口的类型,路径,括号里面对应的就是接口的路径,这里不赘述

💡实际开发优化:使用DTO进行参数校验

js 复制代码
// app.service
import { Injectable } from '@nestjs/common';
import { UserService } from './module/user/user.service';

@Injectable()
export class AppService {
  constructor(private readonly userService: UserService) {}
  async getUsers() {
    const res = await this.userService.findAll()
    return { code: 200, msg: 'success', data: res }
  }
  createUser(data) {
    this.userService.create(data)
    return { code: 200, msg: 'success' }
  }
  
  async updateUser(id, data) {
    const res = await this.userService.update(id, data)
    return { code: 200, msg: 'success', data: res }
  }
  
  async deleteUser(id) {
    const res = await this.userService.remove(id)
    return { code: 200, msg: 'success', data: res }
  }
}

💡实际开发优化 :通过try catch 添加错误处理与类型校验

Postman测试结果展示

我们打开postman来试一下

创建用户成功

我们来查询一下

我们将用户名改成 "笨鸟先飞"

再把该用户删除掉

总结

作为一个前端,肯定有想过自己做后端,我的学习动力全是开发驱动学习,当你学习不下的时候,就可以找一些感兴趣的东西,比如我感兴趣 ,相信大家都感兴趣,然后看到好多人通过小程序的广告挣钱,于是就想着开发小程序。

某天刚好朋友教会了我摇骰子作为导火索,看起来好像挺多人玩,于是我就决定自己开发一款有自己设计的小程序,从最开始的第一步 在2d平面实现3d效果的骰子,再到实现 联机功能,最后成果出炉:小程序 骰友局 (可微信搜索体验) 。虽然现在做的小程序还不是那么完美,但当你回看走过的路和成果,即使现在小程序收益每天几分钱,但这个学习的过程才是巨大的收获。

前面说了一大堆题外话,这篇文章也是自己在开发中的学习记录的过程,很适合新手学习 Nest 进行开发,因为自己在开发的时候,踩过一些坑,很多文章没有提及到的点,自己都有写出来。后续有时间还会继续更新 Nest 相关的文章。

相关推荐
八了个戒6 分钟前
「数据可视化 D3系列」入门第六章:比例尺的使用
前端·javascript·信息可视化·数据可视化·canvas
少糖研究所13 分钟前
ACPA算法详解
前端
Mores25 分钟前
开源 | ImageMinify:轻量级智能图片压缩工具,为你的项目瘦身加速
前端
执梦起航26 分钟前
webpack理解与使用
前端·webpack·node.js
ai大师26 分钟前
Cursor怎么使用,3分钟上手Cursor:比ChatGPT更懂需求,用聊天的方式写代码,GPT4、Claude 3.5等先进LLM辅助编程
前端
Json_29 分钟前
使用vue2技术写了一个纯前端的静态网站商城-鲜花销售商城
前端·vue.js·html
1024熙30 分钟前
【Qt】——理解信号与槽,学会使用connect
前端·数据库·c++·qt5
少糖研究所31 分钟前
ColorThief库是如何实现图片取色的?
前端
冴羽31 分钟前
SvelteKit 最新中文文档教程(22)—— 最佳实践之无障碍与 SEO
前端·javascript·svelte
ZYLAB33 分钟前
我写了一个简易的 SEO 教程,希望能让新手朋友看完以后, SEO 能做到 80 分
前端·seo