您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# 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
// 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]
})
// 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()
export class Product {
@Prop({ index: true })
name: string;
@Prop({ index: 'text' })
description: string;
}
// 复合索引
ProductSchema.index({ name: 1, price: -1 });
UserSchema.virtual('fullName').get(function() {
return `${this.firstName} ${this.lastName}`;
});
UserSchema.pre('save', function(next) {
if (this.isModified('password')) {
this.password = hashPassword(this.password);
}
next();
});
// 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();
}
}
// 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();
}
}
@Controller({ path: 'users', version: '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 }
}
]);
}
const explanation = await userModel.find(query).explain();
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 });
try {
await userRepository.create(userData);
} catch (error) {
if (error.code === 11000) {
throw new ConflictException('Duplicate key error');
}
throw error;
}
mongoose.connection.on('error', (err) => {
logger.error(`MongoDB connection error: ${err}`);
process.exit(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的深度整合 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。