MongoDB(Mongoose)
警告
在本文中,你将学习如何基于 Mongoose 包,通过自定义组件从零创建一个 DatabaseModule。因此,这种方案会包含较多样板与额外负担,而这些内容实际上可以通过现成可用的 @nestjs/mongoose 包省略掉。要了解更多内容,请参见这里。
Mongoose 是最流行的 MongoDB 对象建模工具。
入门
要开始使用这个库,我们需要安装所有必需依赖:
$ npm install --save mongoose第一步是使用 connect() 函数与数据库建立连接。connect() 函数会返回一个 Promise,因此我们需要创建一个异步提供者。
// database.providers.ts
import * as mongoose from 'mongoose';
export const databaseProviders = [
{
provide: 'DATABASE_CONNECTION',
useFactory: (): Promise<typeof mongoose> =>
mongoose.connect('mongodb://localhost/nest'),
},
];提示
遵循最佳实践,我们将自定义 provider 声明在一个独立文件中,并使用 *.providers.ts 后缀。
然后,我们需要导出这些 provider,以便应用的其他部分也能访问它们。
// database.module.ts
import { Module } from '@nestjs/common';
import { databaseProviders } from './database.providers';
@Module({
providers: [...databaseProviders],
exports: [...databaseProviders],
})
export class DatabaseModule {}现在我们就可以使用 @Inject() 装饰器注入 Connection 对象。任何依赖 Connection 异步 provider 的类,都会等待对应的 Promise 被解析。
注入模型
在 Mongoose 中,一切都源自 Schema。先来定义 CatSchema:
// schemas/cat.schema.ts
import * as mongoose from 'mongoose';
export const CatSchema = new mongoose.Schema({
name: String,
age: Number,
breed: String,
});CatsSchema 属于 cats 目录,而该目录代表 CatsModule。
现在该创建一个 Model provider 了:
// cats.providers.ts
import { Connection } from 'mongoose';
import { CatSchema } from './schemas/cat.schema';
export const catsProviders = [
{
provide: 'CAT_MODEL',
useFactory: (connection: Connection) => connection.model('Cat', CatSchema),
inject: ['DATABASE_CONNECTION'],
},
];警告
在真实应用中,应避免使用魔法字符串。CAT_MODEL 和 DATABASE_CONNECTION 都应该放在单独的 constants.ts 文件中。
现在我们就可以在 CatsService 中使用 @Inject() 装饰器注入 CAT_MODEL:
// cats.service.ts
import { Model } from 'mongoose';
import { Injectable, Inject } from '@nestjs/common';
import { Cat } from './interfaces/cat.interface';
import { CreateCatDto } from './dto/create-cat.dto';
@Injectable()
export class CatsService {
constructor(
@Inject('CAT_MODEL')
private catModel: Model<Cat>,
) {}
async create(createCatDto: CreateCatDto): Promise<Cat> {
const createdCat = new this.catModel(createCatDto);
return createdCat.save();
}
async findAll(): Promise<Cat[]> {
return this.catModel.find().exec();
}
}在上面的例子中,我们使用了 Cat 接口。这个接口继承自 mongoose 包中的 Document:
import { Document } from 'mongoose';
export interface Cat extends Document {
readonly name: string;
readonly age: number;
readonly breed: string;
}数据库连接是异步的,但 Nest 让整个过程对最终用户几乎完全透明。CatModel 类会等待数据库连接完成,而 CatsService 也会延迟到 model 准备就绪之后才实例化。整个应用会在所有类都完成实例化后再启动。
下面是最终的 CatsModule:
// cats.module.ts
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
import { catsProviders } from './cats.providers';
import { DatabaseModule } from '../database/database.module';
@Module({
imports: [DatabaseModule],
controllers: [CatsController],
providers: [
CatsService,
...catsProviders,
],
})
export class CatsModule {}提示
别忘了在根 AppModule 中导入 CatsModule。
示例
一个可运行的示例见这里。