前沿
Nestjs提供了两种方法集成MongoDB。一种是通过内置的TypeORM模块(内置有MongoDB连接器),另一种是利用Mongoose对MongoDB进行集成。本文主要实践第二种方法。
安装依赖
首先安装所需的依赖项:
npm install --save @nestjs/mongoose mongoose
连接数据库
方法一
首先是将MongooseModule导入到根模块AppModule中。使用MongooseModule.forRoot()
方法,接收一个和Mongoose .connect()
相同的配置对象,如下所示:
@@filename(app.module)
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
@Module({
imports: [MongooseModule.forRoot(`mongodb://${account}:${password}@${host}:${port}/${db}`)]
})
export class AppModule {}
查看MongooseModule
类的定义,forRoot(uri, options?)
还接收一个options
参数,这个配置参数支持配置Mongodb的其他配置项。
可以看下它们的继承关系:
所以,一些常用的配置都可以在这里完成。
方法二:异步获取配置
当我们需要异步获取配置信息的时候,可以使用forRootAsync()
方法,传入一个工厂函数useFactory()
获取配置,如下:
MongooseModule.forRootAsync({
useFactory: async () => {
// 一些异步获取操作
let uri = `mongodb://${account}:${password}@${host}:${port}/${db}`;
return { uri };
},
});
也可以通过inject
注入依赖项,此处是通过Nest内置的ConfigModule
模块将配置信息提取,统一管理:
MongooseModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
uri: configService.get<string>('MONGODB_URI'),
}),
inject: [ConfigService],
});
定义schema
我们都知道每个Schema都映射到一个MongoDB的集合,负责从底层MongoDB数据库创建和读取文档。接下来使用Nestjs装饰器创建数据模型Schema。
创建user.schema.ts
文件,配置如下:
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
// Schema装饰器同样接受一个options参数,让我们按意愿配置数据模型
// 同new mongoose.Schema(_, options)中的options配置一样,具体详情可查阅mongoose文档
@Schema({
// 配置集合名称。如果不配置此项的话,默认会取类名并加上一个's',数据库内的集合名称就是'users'
collection: 'user',
// timestamps是用来配置createdAt和updatedAt的。默认为false不创建,可按需求自定义
timestamps: {
createdAt: 'time',
updatedAt: false
},
// 这里是对toJSON()方法进行配置,toJSON()方法是用来把查询出来的数据库数据对象转换成普通对象
// 数据库默认都有一个_id,是ObjectId类型,同时为其制定一个虚拟映射id,string类型
// virtuals是控制id字段是否显示的,默认为false
// transform是对结果文档做一些操作,常见的就是去掉_id,只保留id
toJSON: {
virtuals: true,
transform: (doc, ret, opt) => {
delete ret._id;
}
}
})
export class User {
// Prop装饰器是用来配置属性的,比如定义属性类型,是否必填等,具体可参考文档
@Prop({ required: true })
name: string;
@Prop({ required: true })
pwd: string;
@Prop({ required: true })
mobile: string;
}
export const UserSchema = SchemaFactory.createForClass(User);
export type UserDocument = User & Document;
注入schema
定义好Schema后,在需要使用的模块注入,比如在UserModule
中:
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { UserController } from './user.controller';
import { UserService } from './user.service';
import { User, UserSchema } from './schemas/user.schema';
@Module({
// 在这个模块中,可能会操作数据库的很多集合,把需要的Schema注入到这里
imports: [MongooseModule.forFeature([
{ name: User.name, schema: UserSchema }
// ...
])],
controllers: [UserController],
providers: [UserService],
})
export class UserModule {}
然后在需要操作数据库的地方注入UserModel
进行数据库操作,比如UserService
:
import { Model } from 'mongoose';
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { User, UserDocument } from './schemas/user.schema';
@Injectable()
export class UserService {
constructor(@InjectModel(User.name) private userModel: Model<UserDocument>) {}
async create(createUserDto): Promise<User> {
const user = await (await this.userModel.create(createUserDto)).toJSON();
return user;
}
}
钩子函数
当我们想注册像pre
或post
这样的钩子函数的时候,需要在Schema注册之前,注册钩子。因为在编译Schema后调用pre()
或post()
在Mongoose中不起作用。所以需要使用forFeatureAsync()
方法以及工厂函数useFactory()
,使用方法如下:
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { UserController } from './user.controller';
import { UserService } from './user.service';
import { User, UserSchema } from './schemas/user.schema';
@Module({
// 在这个模块中,可能会操作数据库的很多集合,把需要的Schema注入到这里
imports: [MongooseModule.forFeatureAsync([
{
name: User.name,
useFactory: () => {
const schema = UserSchema;
schema.pre('save', function() { // 一些操作 });
return schema; // 最后一定要返回schema,否则注入无效
}
},
// ...
])],
controllers: [UserController],
providers: [UserService],
})
export class UserModule {}
总结
以上内容官网均有涉及,浅浅记录,不值一提。如有错误,欢迎指正!!!