如何在 Nestjs 中创建 mongodb 连接提供程序
Posted
技术标签:
【中文标题】如何在 Nestjs 中创建 mongodb 连接提供程序【英文标题】:How to create a mongodb connection provider in Nestjs 【发布时间】:2020-06-06 07:34:35 【问题描述】:我正在尝试在 Nestjs 中为 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
构造函数中。但是构造函数在 db 连接之前运行。
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'
);
【问题讨论】:
因此,此解决方案包含大量开销,您可以使用即用型和可用的开箱即用专用 @nestjs/mongoose 包省略这些开销。 【参考方案1】:我找到了解决方案。这是因为 useFactory
需要一个承诺,因为它是一个 async
函数。所以我将MongoClient.connect()
包裹在Promise
中以解析数据库连接。现在它会等到 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'));
);
)
,
];
【讨论】:
【参考方案2】:是因为调用回调后,返回的连接对象基本丢失了。如果您必须使用工厂提供程序,您可以尝试在 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)
【讨论】:
我不能使用类提供程序,因为类MongoDbProvider
将调用构造函数,但不会等到建立数据库连接。所以控制器中的db
对象将为空。【参考方案3】:
这是我使用 NodeJS 原生驱动程序和 async/await
连接到 MongoDB 的方法:
import MongoClient, Db from 'mongodb';
export const databaseProviders = [
provide: 'DATABASE_CONNECTION',
useFactory: async (): Promise<Db> =>
try
const client = await MongoClient.connect('mongodb://localhost:27017',
useUnifiedTopology: true,
);
return client.db('my_db');
catch (e)
throw e;
,
];
在我写的这篇文章中有一个完整的实现https://medium.com/@gusiol/nestjs-with-mongodb-native-driver-9d82e377d55。
【讨论】:
【参考方案4】:// We can also use MongoClient in nestJs using DipendencyInjection
// first we have to create database connection
// fileName :- db/dbConnection.service.ts
import Injectable from '@nestjs/common';
import MongoClient from 'mongodb';
import config from 'dotenv';
config();
let dbInstance;
const url = process.env.MONGO_URL || 'mongodb://localhost:27017/SocialUserEr';
@Injectable()
export class DbConnection constructor()
this.connect();
connect()
const client = new MongoClient(url);
client
.connect()
.then((connection) =>
dbInstance = connection.db();
console.log('Database connection Succeeded');
)
.catch((err) =>
console.log(err);
);
db()
if (dbInstance) return dbInstance;
Then we have to export it for use anywhere: ex
// fileName:- db/db.module.ts
import Module from '@nestjs/common';
import DbConnection from './db.service';
@Module(
imports: [],
exports: [DbConnection],
providers: [DbConnection],
)
export class DbModule
// for Using this connection inside a module you have to import DbModule : ex
// In this module we want to use db connection so we have to import db module
// fileName:- auth/auth.module.ts
import Module from '@nestjs/common';
import DbModule from 'src/db/db.module';
import AuthController from './auth.controller';
import AuthService from './auth.service';
@Module(
imports: [DbModule],
controllers: [AuthController],
providers: [AuthService],
)
export class AuthModule
// And lastly for using inside any module you have to just
// fileName :- auth.service.ts
import Injectable from '@nestjs/common';
import DbConnection from 'src/db/db.service';
@Injectable()
export class AuthService
constructor(private database: DbConnection)
async createUser(userInfo)
console.log(userInfo);
return await this.database.db().collection('user').insertOne(userInfo);
<!-- begin snippet: js hide: false console: true babel: false -->
【讨论】:
您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。【参考方案5】:就让你useFactory
await
export const databaseProviders = [
provide: "MAIN_DATABASE_CONNECTION",
useFactory: async (): Promise<mongodb.Db> =>
try
const client = await mongodb.MongoClient.connect(process.env.CLUSTER,
);
const db = client.db("dbName");
return db;
catch (error)
throw error;
,
]
【讨论】:
这个问题一年多以前就已经回答过了。请不要添加不能改善现有答案的答案。以上是关于如何在 Nestjs 中创建 mongodb 连接提供程序的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 typeORM 在 Nestjs 中创建类型为 Date 的列并键入 DateTime?
部署在 NX monorepo 中创建的 nestjs 服务器
通过 java 应用程序连接在 mongolab 中创建的 mongodb