NestJS Logo

MongoDB (Mongoose)

Attention Dans cet article, vous apprendrez comment créer un DatabaseModule basé sur le package Mongoose à partir de zéro en utilisant des composants personnalisés. En conséquence, cette solution contient beaucoup de surcharge que vous pouvez omettre en utilisant le package dédié @nestjs/mongoose prêt à l'emploi et disponible prêt à l'emploi. Pour en savoir plus, voir ici.

Mongoose est l'outil de modélisation d'objets MongoDB le plus populaire.

Pour commencer#

Pour commencer l'aventure avec cette bibliothèque, nous devons installer toutes les dépendances nécessaires :


$ npm install --save mongoose

La première étape est d'établir une connexion avec notre base de données en utilisant la fonction connect(). La fonction connect() retourne une Promise, et donc nous devons créer un async provider.

database.providers.ts
JS TS

import * as mongoose from 'mongoose';

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

import * as mongoose from 'mongoose';

export const databaseProviders = [
  {
    provide: 'DATABASE_CONNECTION',
    useFactory: () => mongoose.connect('mongodb://localhost/nest'),
  },
];
Astuce En suivant les meilleures pratiques, nous avons déclaré le fournisseur personnalisé dans le fichier séparé qui a un suffixe *.providers.ts.

Ensuite, nous devons exporter ces fournisseurs pour les rendre accessibles pour le reste de l'application.

database.module.ts
JS TS

import { Module } from '@nestjs/common';
import { databaseProviders } from './database.providers';

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

Maintenant nous pouvons injecter l'objet Connection en utilisant le décorateur @Inject(). Chaque classe qui dépendrait du fournisseur asynchrone Connection attendra jusqu'à ce qu'une Promise soit résolue.

Injection de modèle#

Avec Mongoose, tout est dérivé d'un Schema. Définissons le CatSchema :

schemas/cat.schema.ts
JS TS

import * as mongoose from 'mongoose';

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

Le CatsSchema appartient au répertoire cats. Ce répertoire représente le CatsModule.

Il est maintenant temps de créer un fournisseur Model :

cats.providers.ts
JS 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'],
  },
];

import { CatSchema } from './schemas/cat.schema';

export const catsProviders = [
  {
    provide: 'CAT_MODEL',
    useFactory: (connection) => connection.model('Cat', CatSchema),
    inject: ['DATABASE_CONNECTION'],
  },
];
Attention Dans les applications réelles, vous devriez éviter les magic strings. Le CAT_MODEL et le DATABASE_CONNECTION doivent être conservés dans le fichier constants.ts séparé.

Maintenant nous pouvons injecter le CAT_MODEL dans le CatsService en utilisant le décorateur @Inject() :

cats.service.ts
JS 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();
  }
}

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();
  }
}

Dans l'exemple ci-dessus, nous avons utilisé l'interface Cat. Cette interface étend l'interface Document du package mongoose :


import { Document } from 'mongoose';

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

La connexion à la base de données est asynchrone, mais Nest rend ce processus complètement invisible pour l'utilisateur final. La classe CatModel attend la connexion à la base de données, et le CatsService est retardé jusqu'à ce que le modèle soit prêt à être utilisé. L'application entière peut démarrer lorsque chaque classe est instanciée.

Voici la version finale de CatsModule :

cats.module.ts
JS 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 {}
Astuce N'oubliez pas d'importer le CatsModule dans la racine AppModule.

Exemple#

Un exemple concret est disponible ici.

Soutenez-nous

Nest est un projet open source sous licence MIT. Il peut se développer grâce au soutien de ces personnes formidables. Si vous souhaitez les rejoindre, apprenez-en plus ici.

Sponsors Principaux

Trilon LogoMarblism LogoMojam LogoAmplication Logo

Sponsors / Partenaires

Devenir un sponsor