Как создать провайдер mongodb в Nestjs - PullRequest
0 голосов
/ 21 февраля 2020

Я пытаюсь создать провайдер соединения с базой данных в Nest js для MongoDB.

Я проверил user.controller.ts и mongoDbProvider, установив точки останова, и обнаружил, что контроллер получает до установления соединения с базой данных. Как установить соединение с базой данных до инициализации контроллеров? В документации

Nest. js говорится, что метод useFactory будет запускаться перед любым другим модулем, который зависит от него.

src/mongo-db/mongodb.provider.ts

import { MongoClient } from "mongodb";
import { MONGODB_PROVIDER } from "../constants";

export const mongoDbProviders = [
  {
    provide: MONGODB_PROVIDER,
    useFactory: async () => {
      MongoClient.connect('mongodb://localhost:27017',
        { useUnifiedTopology: true },
        (error, client) => {
          return client.db('nestjs-sample');
        });
    }
  },

];

src/mongo-db/mongo-db.module.ts

import { mongoDbProviders } from './mongo-db.providers';

@Module({
  providers: [...mongoDbProviders],
  exports: [...mongoDbProviders],
})
export class MongoDbModule {

}

src/constants.ts

export const MONGODB_PROVIDER = 'MONGODB_CONNECTION';

Я импортировал MongoDbModule в user.module.ts

src/user/user.module.ts

import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { UserService } from './user.service';
import { MongoDbModule } from 'src/mongo-db/mongo-db.module';

@Module({
  imports: [MongoDbModule],
  controllers: [UserController],
  providers: [UserService]
})
export class UserModule {}

Здесь я вставил db из mongoDbProvider в UserController конструктор. Но конструктор запускается до соединения с БД.

src/user/user.controller.ts

import { Controller, Post, Req, Get, Res, Inject } from '@nestjs/common';
import { Request, Response } from "express";
import { MONGODB_PROVIDER } from 'src/constants';

@Controller('users')
export class UserController {

  constructor(@Inject(MONGODB_PROVIDER) private readonly db: any) {

  }

  @Post()
  async create(@Req() request: Request, @Res() response: Response) {
    this.db.collection('users').insertOne(request.body, (err, result) => {
      if (err) {
        response.status(500).json(err);
      } else {
        response.status(201);
        response.send(result);
      }
    });
  }

  @Get()
  get(@Req() request: Request, @Res() response: Response) {
    response.status(400).json({
      message: 'kidilam service'
    });
  }

}

Ответы [ 2 ]

1 голос
/ 22 февраля 2020

Я нашел решение. Это потому, что useFactory ожидает обещание, потому что это async функция. Поэтому я обернул MongoClient.connect() внутри Promise, чтобы разрешить соединение с базой данных. Теперь он ожидает разрешения обещания, прежде чем инициализировать все модули, которые зависят от него.

import { MongoClient } from "mongodb";
import { MONGODB_PROVIDER } from "../constants";

export const mongoDbProviders = [
  {
    provide: MONGODB_PROVIDER,
    useFactory: async () => new Promise((resolve, reject) => {
      MongoClient.connect('mongodb://localhost:27017',
      { useUnifiedTopology: true },
      (error, client) => {
        if (error) {
          reject(error);
        } else {
          resolve(client.db('nestjs-sample'));
        }
      });
    })
  },
];
0 голосов
/ 22 февраля 2020

Это потому, что после вызова обратного вызова возвращаемый объект соединения в основном теряется. Если вам необходимо использовать провайдера фабрики, вы можете попробовать использовать замыкание в обратном вызове MongoClient.connect вместе с провайдером значений. Я имею в виду такой подход:

import { MongoClient } from "mongodb";
import { MONGODB_PROVIDER } from "../constants";

const MONGODB_PROVIDER_RESOLVED = 'MONGODB_PROVIDER_RESOLVED'
let connection = undefined;
export const mongoDbProviders = [
  {
    provide: MONGODB_PROVIDER_RESOLVED,
    useValue: connection
  },
  {
    provide: MONGODB_PROVIDER,
    useFactory: async () => {
      MongoClient.connect('mongodb://localhost:27017',
        { useUnifiedTopology: true },
        (error, client) => {
          connection = client.db('nestjs-sample');
        });

    }
  },

];

Затем введите и MONGODB_PROVIDER, и MONGODB_PROVIDER_RESOLVED:

constructor(@Inject(MONGODB_PROVIDER) private readonly _db: any, @Inject(MONGODB_PROVIDER) private readonly db: any) 

Первое внедрение зависимостей заставит работать код вашей фабрики. Второй будет содержать разрешенное соединение. Это немного неуклюже, я согласен. Что может быть лучше, так это использование поставщика классов:

import { Injectable } from '@nestjs/common';
@Injectable()
export class MongoDBProvider {
    connection
    constructor(){
      MongoClient.connect('mongodb://localhost:27017',
            { useUnifiedTopology: true },
            ((error, client) => {
              this.connection = client.db('nestjs-sample');
            }).bind(this));
    }
}

Теперь вы можете использовать его в своем контроллере:

constructor( private readonly db: MongoDBProvider) {

  }
...