Mongo数据库

Mongo数据库

有两种方法可以处理 MongoDB 数据库。您可以使用提供 MongoDB 支持的 ORM,也可以使用最受欢迎的 MongoDB 对象建模工具 Mongoose 。如果您想使用 ORM,可以按照以下步骤操作。否则,我们将使用专用包。@nestjs/mongoose

首先,我们需要安装所有必需的依赖项:

$ npm install --save @nestjs/mongoose mongoose

安装过程完成后,我们可以将其MongooseModule导入到根目录中ApplicationModule

app.module.ts

JS

import { Module } from '@nestjs/common'; import { MongooseModule } from '@nestjs/mongoose'; @Module{ imports: [MongooseModule.forRoot('mongodb://localhost/nest')], }) export class ApplicationModule {}

forRoot()方法接受相同的配置对象作为mongoose.connect()从猫鼬包。

模型注射

使用Mongoose,一切都来自Schema。让我们来定义CatSchema

猫/模式/ cat.schema.ts

JS

import * as mongoose from 'mongoose'; export const CatSchema = new mongoose.Schema{ name: String, age: Number, breed: String, }

CatsSchema属于cats目录。这个目录代表了CatsModule。这是您决定保留架构文件的决定。从我们的角度来看,在相应的模块目录中,最好的方法是将它们保存在几乎所有的域中

我们来看看CatsModule

猫/ cats.module.ts

JS

import { Module } from '@nestjs/common'; import { MongooseModule } from '@nestjs/mongoose'; import { CatsController } from './cats.controller'; import { CatsService } from './cats.service'; import { CatSchema } from './schemas/cat.schema'; @Module{ imports: [MongooseModule.forFeature([{ name: 'Cat', schema: CatSchema }])], controllers: [CatsController], providers: [CatsService], }) export class CatsModule {}

该模块使用forFeature()方法来定义哪些模型应在当前范围内注册。多亏了这一点,我们可以注入CatModel的到CatsService用的@InjectModel()装饰:

猫/ cats.service.ts

JS

import { Model } from 'mongoose'; import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Cat } from './interfaces/cat.interface'; import { CreateCatDto } from './dto/create-cat.dto'; @Injectable() export class CatsService { constructor(@InjectModel('Cat') private readonly catModel: Model<Cat>) {} async create(createCatDto: CreateCatDto): Promise<Cat> { const createdCat = new this.catModel(createCatDto return await createdCat.save( } async findAll(): Promise<Cat[]> { return await this.catModel.find().exec( } }

测试

在单元测试我们的应用程序时,我们通常希望避免任何数据库连接,使我们的测试套件独立并尽可能快地执行它们。但是我们的类可能依赖于从连接实例中提取的模型。那是什么?解决方案是创建假模型。为了实现这一点,我们应该设置自定义提供程序。实际上,每个注册的模型都由NameModeltoken表示,其中Name是模型的名称。

@nestjs/mongoose包公开了getModelToken()基于给定模型名称返回准备好的令牌的函数。

@Module{ providers: [ CatsService, { provide: getModelToken('Cat'), useValue: catModel, }, ], }) export class CatsModule {}

现在硬编码catModel将被用作Model<Cat>。每当任何提供者要求Model<Cat>使用@InjectModel()装饰器时,Nest将使用注册的catModel对象。

异步配置

通常,您可能希望异步传递模块选项,而不是事先传递它们。在这种情况下,使用forRootAsync()方法,提供了几种处理异步数据的方法。

第一种可能的方法是使用工厂功能:

MongooseModule.forRootAsync{ useFactory: () => { uri: 'mongodb://localhost/nest', }), })

显然,我们的工厂表现得像其他每一个(可能async并且能够通过注入依赖关系inject)。

MongooseModule.forRootAsync{ imports: [ConfigModule], useFactory: async (configService: ConfigService) => { uri: configService.getString('MONGODB_URI'), }), inject: [ConfigService], })

或者,您可以使用类而不是工厂。

MongooseModule.forRootAsync{ useClass: MongooseConfigService, })

上面的构造将MongooseConfigService在内部实例化MongooseModule,并将利用它来创建选项对象。在MongooseConfigService必须实现MongooseOptionsFactory的接口。

@Injectable() class MongooseConfigService implements MongooseOptionsFactory { createMongooseOptions(): MongooseModuleOptions { return { uri: 'mongodb://localhost/nest', }; } }

为了防止MongooseConfigService内部创建MongooseModule并使用从不同模块导入的提供程序,您可以使用useExisting语法。

MongooseModule.forRootAsync{ imports: [ConfigModule], useExisting: ConfigService, })

它的作用useClass与一个关键区别相同 - MongooseModule将查找导入的模块以重新使用已创建的ConfigService,而不是单独实例化它。