node中如何使用Nest.js连接MongoDB数据库

发布时间:2022-01-27 09:34:28 作者:柒染
来源:亿速云 阅读:284
# Node中如何使用Nest.js连接MongoDB数据库

## 目录
1. [Nest.js与MongoDB概述](#nestjs与mongodb概述)
2. [环境准备与项目初始化](#环境准备与项目初始化)
3. [MongoDB模块配置](#mongodb模块配置)
4. [定义数据模型与Schema](#定义数据模型与schema)
5. [Repository模式实现](#repository模式实现)
6. [服务层与业务逻辑](#服务层与业务逻辑)
7. [控制器与路由处理](#控制器与路由处理)
8. [高级查询与聚合操作](#高级查询与聚合操作)
9. [性能优化与最佳实践](#性能优化与最佳实践)
10. [常见问题解决方案](#常见问题解决方案)

---

## Nest.js与MongoDB概述

### 为什么选择Nest.js + MongoDB组合
Nest.js是一个基于TypeScript的渐进式Node.js框架,结合了OOP(面向对象编程)、FP(函数式编程)和FRP(函数响应式编程)的理念。MongoDB作为领先的NoSQL数据库,具有以下优势:
- 文档型数据模型(BSON格式)
- 灵活的模式设计
- 水平扩展能力
- 丰富的查询语言

两者结合特别适合:
- 快速迭代的现代Web应用
- 需要处理非结构化数据的场景
- 微服务架构中的数据存储

### 技术栈核心组件
| 组件              | 作用                          |
|-------------------|-----------------------------|
| @nestjs/mongoose  | 官方MongoDB集成包             |
| mongoose          | MongoDB对象建模工具           |
| Typegoose         | 用TypeScript类定义模型的替代方案 |

---

## 环境准备与项目初始化

### 系统要求
- Node.js 16+
- MongoDB 4.4+
- npm 8+ 或 yarn 1.22+

### 创建Nest项目
```bash
npm i -g @nestjs/cli
nest new nest-mongo-demo
cd nest-mongo-demo

安装依赖

npm install @nestjs/mongoose mongoose
npm install --save-dev @types/mongoose

项目结构规划

/src
├── /modules
│   ├── /database
│   ├── /users
│   └── /products
├── main.ts
└── app.module.ts

MongoDB模块配置

基本连接配置

// app.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';

@Module({
  imports: [
    MongooseModule.forRoot('mongodb://localhost:27017/nest-demo', {
      connectionFactory: (connection) => {
        connection.on('connected', () => {
          console.log('MongoDB connected successfully');
        });
        return connection;
      }
    })
  ]
})
export class AppModule {}

多环境配置方案

// config/configuration.ts
export default () => ({
  database: {
    uri: process.env.MONGO_URI || 'mongodb://localhost:27017/nest-demo',
    options: {
      useNewUrlParser: true,
      useUnifiedTopology: true,
      authSource: 'admin',
      user: process.env.MONGO_USER,
      pass: process.env.MONGO_PASS
    }
  }
});

// app.module.ts
MongooseModule.forRootAsync({
  useFactory: (config: ConfigService) => ({
    uri: config.get<string>('database.uri'),
    ...config.get('database.options')
  }),
  inject: [ConfigService]
})

定义数据模型与Schema

基础模型定义

// users/schemas/user.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

@Schema({ timestamps: true })
export class User extends Document {
  @Prop({ required: true })
  username: string;

  @Prop({ required: true, select: false })
  password: string;

  @Prop({ required: true, unique: true })
  email: string;

  @Prop({ default: false })
  isVerified: boolean;
}

export const UserSchema = SchemaFactory.createForClass(User);

高级Schema配置技巧

  1. 索引优化
@Schema()
export class Product {
  @Prop({ index: true })
  name: string;

  @Prop({ index: 'text' })
  description: string;
}

// 复合索引
ProductSchema.index({ name: 1, price: -1 });
  1. 虚拟属性
UserSchema.virtual('fullName').get(function() {
  return `${this.firstName} ${this.lastName}`;
});
  1. 中间件钩子
UserSchema.pre('save', function(next) {
  if (this.isModified('password')) {
    this.password = hashPassword(this.password);
  }
  next();
});

Repository模式实现

标准Repository实现

// users/repositories/user.repository.ts
import { Model } from 'mongoose';
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { User } from '../schemas/user.schema';

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

  async create(createUserDto: any): Promise<User> {
    const createdUser = new this.userModel(createUserDto);
    return createdUser.save();
  }

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

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

动态查询构建器

async findWithPagination(
  query: any,
  page: number,
  limit: number
): Promise<{ data: User[]; total: number }> {
  const [data, total] = await Promise.all([
    this.userModel
      .find(query)
      .skip((page - 1) * limit)
      .limit(limit)
      .exec(),
    this.userModel.countDocuments(query).exec()
  ]);
  
  return { data, total };
}

服务层与业务逻辑

基础服务示例

// users/services/user.service.ts
import { Injectable } from '@nestjs/common';
import { UserRepository } from '../repositories/user.repository';

@Injectable()
export class UserService {
  constructor(private readonly userRepository: UserRepository) {}

  async createUser(createUserDto: any) {
    // 业务逻辑验证
    if (await this.userRepository.exists({ email: createUserDto.email })) {
      throw new Error('Email already exists');
    }
    return this.userRepository.create(createUserDto);
  }
}

事务处理

async transferFunds(senderId: string, receiverId: string, amount: number) {
  const session = await this.userModel.db.startSession();
  session.startTransaction();
  
  try {
    const sender = await this.userModel.findByIdAndUpdate(
      senderId,
      { $inc: { balance: -amount } },
      { session }
    ).exec();

    const receiver = await this.userModel.findByIdAndUpdate(
      receiverId,
      { $inc: { balance: amount } },
      { session }
    ).exec();

    await session.commitTransaction();
    return { sender, receiver };
  } catch (error) {
    await session.abortTransaction();
    throw error;
  } finally {
    session.endSession();
  }
}

控制器与路由处理

RESTful控制器实现

// users/controllers/user.controller.ts
import { Controller, Get, Post, Body } from '@nestjs/common';
import { UserService } from '../services/user.service';

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

  @Post()
  async create(@Body() createUserDto: any) {
    return this.userService.createUser(createUserDto);
  }

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

高级路由技巧

  1. 版本控制
@Controller({ path: 'users', version: '1' })
  1. 文件上传处理
@Post('avatar')
@UseInterceptors(FileInterceptor('file'))
async uploadAvatar(
  @UploadedFile() file: Express.Multer.File,
  @User() user: User
) {
  return this.userService.updateAvatar(user._id, file);
}

高级查询与聚合操作

复杂查询示例

// 多条件联合查询
async findActiveUsers(minAge: number) {
  return this.userModel.find({
    age: { $gte: minAge },
    isActive: true,
    lastLogin: { $gte: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000) }
  }).sort({ createdAt: -1 });
}

聚合管道实战

async getUserStats() {
  return this.userModel.aggregate([
    {
      $match: { isActive: true }
    },
    {
      $group: {
        _id: '$role',
        count: { $sum: 1 },
        averageAge: { $avg: '$age' }
      }
    },
    {
      $sort: { count: -1 }
    }
  ]);
}

性能优化与最佳实践

索引优化策略

  1. EXPLN分析
const explanation = await userModel.find(query).explain();
  1. 覆盖索引
UserSchema.index({ email: 1 }, { unique: true });

连接池配置

MongooseModule.forRoot(uri, {
  poolSize: 20, // 默认5
  socketTimeoutMS: 45000,
  connectTimeoutMS: 30000
})

读写分离

const readPreference = process.env.NODE_ENV === 'production' 
  ? 'secondaryPreferred' 
  : 'primary';
  
MongooseModule.forRoot(uri, { readPreference });

常见问题解决方案

典型错误处理

  1. 重复键错误
try {
  await userRepository.create(userData);
} catch (error) {
  if (error.code === 11000) {
    throw new ConflictException('Duplicate key error');
  }
  throw error;
}
  1. 连接问题
mongoose.connection.on('error', (err) => {
  logger.error(`MongoDB connection error: ${err}`);
  process.exit(1);
});

迁移策略

  1. 数据迁移脚本
async function migrateUserData() {
  const batchSize = 100;
  let processed = 0;
  
  const cursor = oldUserModel.find().cursor();
  
  for await (const doc of cursor) {
    await newUserModel.create(transformData(doc));
    processed++;
    
    if (processed % batchSize === 0) {
      console.log(`Processed ${processed} documents`);
    }
  }
}

总结

本文详细介绍了在Nest.js中集成MongoDB的全流程,从基础连接到高级优化,涵盖了: - 模块化数据库配置 - 类型安全的Schema设计 - 分层的应用架构 - 事务处理和聚合查询 - 生产环境最佳实践

通过合理运用这些技术,您可以构建出高性能、易维护的Node.js后端服务。建议进一步探索: - MongoDB Atlas云服务集成 - 分布式事务处理 - 与GraphQL的深度整合 “`

推荐阅读:
  1. 使用Node怎么对MongoDB数据库进行操作
  2. 使用node.js如何连接mysql

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

nest.js node mongodb

上一篇:Vue框架怎么使用

下一篇:Linux系统怎么格式化USB设备

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》