Mongo
Nest prend en charge deux méthodes pour s’intégrer à la base de données MongoDB. Vous pouvez soit utiliser le module intégré TypeORM décrit ici, qui a un connecteur pour MongoDB, soit utiliser Mongoose, le modèle d’objet MongoDB le plus populaire. Dans ce chapitre, nous allons décrire ce dernier, en utilisant le package dédié @nestjs/mongoose
.
Commencez par installer les dépendances requises :
npm i @nestjs/mongoose mongoose
Une fois le processus d’installation terminé, nous pouvons importer le MongooseModule
dans le module principal AppModule
.
import { Module } from '@nestjs/common';import { MongooseModule } from '@nestjs/mongoose';
@Module({ imports: [MongooseModule.forRoot('mongodb://localhost/nest')],})export class AppModule {}
La méthode forRoot()
accepte le même objet de configuration que mongoose.connect()
du paquet Mongoose, comme décrit ici.
Injection de modèle
Avec Mongoose, tout est dérivé d’un Schema. Chaque schéma correspond à une collection MongoDB et définit la forme des documents dans cette collection. Les schémas sont utilisés pour définir des Modèles. Les modèles sont responsables de la création et de la lecture des documents à partir de la base de données MongoDB sous-jacente.
Les schémas peuvent être créés avec des décorateurs NestJS ou avec Mongoose lui-même manuellement. Utiliser des décorateurs pour créer des schémas réduit considérablement le boilerplate et améliore la lisibilité du code.
Définissons le CatSchema
:
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';import { HydratedDocument } from 'mongoose';
export type CatDocument = HydratedDocument<Cat>;
@Schema()export class Cat { @Prop() name: string;
@Prop() age: number;
@Prop() breed: string;}
export const CatSchema = SchemaFactory.createForClass(Cat);
Le décorateur @Schema()
marque une classe comme définition de schéma. Il associe notre classe Cat
à une collection MongoDB du même nom, mais avec un “s” supplémentaire à la fin - donc le nom final de la collection mongo sera cats
. Ce décorateur accepte un seul argument optionnel qui est un objet d’options de schéma. Pensez à cela comme l’objet que vous passeriez normalement comme deuxième argument du constructeur de la classe mongoose.Schema
(par exemple, new mongoose.Schema(_, options)
). Pour en savoir plus sur les options de schéma disponibles, consultez ce chapitre.
Le décorateur @Prop()
définit une propriété dans le document. Par exemple, dans la définition de schéma ci-dessus, nous avons défini trois propriétés : name
, age
, et breed
. Les types de schéma pour ces propriétés sont automatiquement inférés grâce aux capacités de métadonnées (et de réflexion) de TypeScript. Cependant, dans des scénarios plus complexes où les types ne peuvent pas être reflétés implicitement (par exemple, des tableaux ou des structures d’objets imbriquées), les types doivent être indiqués explicitement, comme suit :
@Prop([String])tags: string[];
Alternativement, le décorateur @Prop()
accepte un objet d’options de paramètre (lisez plus sur les options disponibles ici). Avec cela, vous pouvez indiquer si une propriété est requise ou non, spécifier une valeur par défaut, ou la marquer comme immuable. Par exemple :
@Prop({ required: true })name: string;
Si vous souhaitez spécifier la relation à un autre modèle, plus tard pour le remplissage, vous pouvez également utiliser le décorateur @Prop()
. Par exemple, si Cat
a Owner
qui est stocké dans une collection différente appelée owners
, la propriété devrait avoir un type et une référence. Par exemple :
import * as mongoose from 'mongoose';import { Owner } from '../owners/schemas/owner.schema';
class Cat { @Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'Owner' }) owner: Owner;}
Connexion
Il se peut que vous ayez besoin d’accéder à l’objet de connexion Mongoose natif. Par exemple, vous voudrez peut-être effectuer des appels API natifs sur l’objet de connexion. Vous pouvez injecter la connexion Mongoose en utilisant le décorateur @InjectConnection()
comme suit :
import { Injectable } from '@nestjs/common';import { InjectConnection } from '@nestjs/mongoose';import { Connection } from 'mongoose';
@Injectable()export class CatsService { constructor( @InjectConnection() private connection: Connection, ) {}}
Bases de données multiples
Certains projets nécessitent plusieurs connexions à la base de données. Cela peut également être réalisé avec ce module. Pour travailler avec plusieurs connexions, commencez par créer les connexions. Dans ce cas, le nommage des connexions devient obligatoire.
import { Module } from '@nestjs/common';import { MongooseModule } from '@nestjs/mongoose';
@Module({ imports: [ MongooseModule.forRoot('mongodb://localhost/test', { connectionName: 'cats', }), MongooseModule.forRoot('mongodb://localhost/users', { connectionName: 'users', }), ],})export class AppModule {}
Avec cette configuration, vous devez indiquer à la fonction MongooseModule.forFeature()
quelle connexion doit être utilisée.
imports: [ MongooseModule.forFeature([{ name: Cat.name, schema: CatSchema }], 'cats'),],
Enfin, le fichier cat.schema
réside dans un dossier du répertoire cats
, où nous définissons également le CatsModule
. Bien que vous puissiez stocker les fichiers de schéma où vous le souhaitez, nous recommandons de les stocker près de leurs objets domaines connexes, dans le répertoire du module approprié.
Test
Lors des tests unitaires d’une application, nous voulons généralement éviter toute connexion à la base de données, rendant nos suites de tests plus simples à configurer et plus rapides à exécuter. Mais nos classes peuvent dépendre de modèles qui sont extraits de l’instance de connexion. Comment résolvons-nous ces classes ? La solution consiste à créer des modèles fictifs.
Pour faciliter cela, le package @nestjs/mongoose
expose une fonction getModelToken()
qui retourne un jeton d’injection préparé basé sur un nom de jeton. En utilisant ce jeton, vous pouvez facilement fournir une implémentation fictive en utilisant n’importe lesquelles des techniques standard de fournisseur personnalisé, y compris useClass
, useValue
, et useFactory
. Par exemple :
import { Module } from '@nestjs/common';import { getModelToken } from '@nestjs/mongoose';
@Module({ providers: [ CatsService, { provide: getModelToken(Cat.name), useValue: catModel, }, ],})export class CatsModule {}
Dans cet exemple, un catModel
codé en dur (instance d’objet) sera fourni chaque fois qu’un consommateur injecte un Model<Cat>
en utilisant un décorateur @InjectModel()
.