跳转至

MongoDB (Mongoose)

警告 在本文中,您将学习如何使用自定义组件创建基于**Mongoose** 包的DatabaseModule。因此,这个解决方案包含了大量的开销,你可以通过使用现成可用的专用@nestjs/mongoose包来省略这些开销。 要了解更多,请参见此处.

Mongoose是目前最流行的MongoDB对象建模工具。

开始

要开始这个库的冒险,我们必须安装所有必需的依赖:

$ npm install --save mongoose

我们需要做的第一步是使用connect()函数建立与数据库的连接。 connect()函数返回一个Promise,因此我们必须创建一个async provider.

1
2
3
4
5
6
7
8
9
import * as mongoose from 'mongoose';

export const databaseProviders = [
  {
    provide: 'DATABASE_CONNECTION',
    useFactory: (): Promise<typeof mongoose> =>
      mongoose.connect('mongodb://localhost/nest'),
  },
];
1
2
3
4
5
6
7
8
import * as mongoose from 'mongoose';

export const databaseProviders = [
  {
    provide: 'DATABASE_CONNECTION',
    useFactory: () => mongoose.connect('mongodb://localhost/nest'),
  },
];

!!! info 提示 按照最佳实践,我们在单独的文件中声明了定制的提供程序,该文件有一个*.providers.ts的后缀。

然后,我们需要导出这些提供器,使应用程序的其余部分能够访问它们。

1
2
3
4
5
6
7
8
import { Module } from '@nestjs/common';
import { databaseProviders } from './database.providers';

@Module({
  providers: [...databaseProviders],
  exports: [...databaseProviders],
})
export class DatabaseModule {}

现在我们可以使用@Inject()装饰器来注入Connection对象。 每个依赖于Connection异步提供程序的类将等待,直到Promise被解析。

模型注入

使用 Mongoose,一切都是从Schema派生出来的。让我们定义CatSchema:

1
2
3
4
5
6
7
import * as mongoose from 'mongoose';

export const CatSchema = new mongoose.Schema({
  name: String,
  age: Number,
  breed: String,
});

CatsSchema属于cats目录。这个目录表示CatsModule

现在是时候创建一个 Model provider 了:

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'],
  },
];
1
2
3
4
5
6
7
8
9
import { CatSchema } from './schemas/cat.schema';

export const catsProviders = [
  {
    provide: 'CAT_MODEL',
    useFactory: (connection) => connection.model('Cat', CatSchema),
    inject: ['DATABASE_CONNECTION'],
  },
];

Warning

在实际应用中,你应该避免使用**魔法字符串** 。CAT_MODELDATABASE_CONNECTION都应该保存在分开的constants.ts文件。

现在我们可以使用@Inject()装饰器将CAT_MODEL注入到CatsService中:

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();
  }
}
import { Injectable, Dependencies } from '@nestjs/common';

@Injectable()
@Dependencies('CAT_MODEL')
export class CatsService {
  constructor(catModel) {
    this.catModel = catModel;
  }

  async create(createCatDto) {
    const createdCat = new this.catModel(createCatDto);
    return createdCat.save();
  }

  async findAll() {
    return this.catModel.find().exec();
  }
}

在上面的例子中,我们使用了Cat接口。这个接口扩展了 mongoose 包中的Document:

1
2
3
4
5
6
7
import { Document } from 'mongoose';

export interface Cat extends Document {
  readonly name: string;
  readonly age: number;
  readonly breed: string;
}

The database connection is asynchronous , but Nest makes this process completely invisible for the end-user. The CatModel class is waiting for the db connection, and the CatsService is delayed until model is ready to use. The entire application can start when each class is instantiated. 数据库连接是 异步 的,但是 Nest 使这个过程对最终用户完全不可见。 CatModel类正在等待数据库连接,而CatsService被延迟到模型准备好使用。 当每个类被实例化时,整个应用程序就可以启动了。

这是最后一个CatsModule:

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 {}

!!! info 提示 不要忘记将CatsModule导入到根模块AppModule中。