Next.js中MongoDB数据库初始化失败问题求助
解决Next.js中MongoDB连接跨页面调用getDb失败的问题
我在Next.js里尝试连接MongoDB,在应用初始化阶段设置了数据库,但在另一个页面调用getDb时失败了。相关代码和报错信息如下:
相关代码
mongo.ts
import { MongoClient, Db, ServerApiVersion } from "mongodb"; let isConnected: boolean = false; const uri: string = process.env.MONGODB_URI as string; const client = new MongoClient(uri, { serverApi: { version: ServerApiVersion.v1, strict: true, deprecationErrors: true, }, }); let db: Db | null = null; async function connect(): Promise<void> { if (!isConnected) { await client.connect(); db = client.db(process.env.MONGO_INITDB_DATABASE); isConnected = true; console.log( "Connected successfully to MongoDB server", getDb().databaseName, ); } } function getDb(): Db { if (!db) { throw new Error( "Database not initialized. Did you forget to call connect first?", ); } return db; } async function close(): Promise<void> { await client.close(); } export { connect, getDb, close };
index.tsx
import { connect } from "@/config/mongo"; ... export async function getServerSideProps(context: any) { try { await connect(); return { props: {} }; } catch (error: any) { return { props: { error: error.message } }; } }
apply.tsx
import { getDb } from "@/config/mongo"; ... export async function getServerSideProps(context: NextPageContext) { console.log( "Inside getServerSideProps of apply.tsx and database connected is ", getDb(), ); }
报错信息
error - config/mongo.ts (35:10) @ getDb error - Error: Database not initialized. Did you forget to call connect first? at getDb (webpack-internal:///./config/mongo.ts:35:15)
问题原因
Next.js的getServerSideProps是每个请求独立执行的,不同页面的请求不会共享内存中的变量。你在index.tsx的getServerSideProps里调用了connect,但这个操作只在访问index页面的请求中初始化了db变量;当访问apply页面时,这是一个全新的请求,内存里的db和isConnected会被重置,所以直接调用getDb会报错。
解决方法
方法1:每个页面的getServerSideProps先调用connect
直接修改apply.tsx的逻辑,确保在调用getDb前先执行连接:
import { getDb, connect } from "@/config/mongo"; ... export async function getServerSideProps(context: NextPageContext) { await connect(); // 先完成数据库连接 console.log( "Inside getServerSideProps of apply.tsx and database connected is ", getDb(), ); return { props: {} }; // 必须返回props,否则Next.js会抛出错误 }
方法2:优化连接复用(推荐)
Next.js生产环境会复用服务器进程,我们可以利用这一点优化连接逻辑,避免重复创建连接,同时兼容开发环境的热重载:
import { MongoClient, Db, ServerApiVersion } from "mongodb"; const uri: string = process.env.MONGODB_URI as string; const dbName: string = process.env.MONGO_INITDB_DATABASE as string; // 全局变量存储实例,避免开发环境热重载重复创建连接 declare global { var mongoClient: MongoClient | undefined; var mongoDb: Db | undefined; } let client: MongoClient; let db: Db; if (process.env.NODE_ENV === "development") { if (!global.mongoClient) { global.mongoClient = new MongoClient(uri, { serverApi: { version: ServerApiVersion.v1, strict: true, deprecationErrors: true, }, }); } client = global.mongoClient; if (!global.mongoDb) { global.mongoDb = client.db(dbName); } db = global.mongoDb; } else { // 生产环境直接创建实例,进程复用会保留连接 client = new MongoClient(uri, { serverApi: { version: ServerApiVersion.v1, strict: true, deprecationErrors: true, }, }); db = client.db(dbName); } async function connect(): Promise<void> { // 检查连接状态,避免重复连接 if (!client.topology || !client.topology.isConnected()) { await client.connect(); console.log("Connected successfully to MongoDB server", db.databaseName); } } function getDb(): Db { if (!db) { throw new Error("Database not initialized. Did you forget to call connect first?"); } return db; } async function close(): Promise<void> { await client.close(); } export { connect, getDb, close };
修改后,每个页面的getServerSideProps仍需先调用connect确保连接状态:
// apply.tsx export async function getServerSideProps(context: NextPageContext) { await connect(); const dbInstance = getDb(); // 在这里执行数据库操作 return { props: {} }; }
关键注意点
- 不要假设不同请求会共享内存变量,每个请求在开发环境可能是全新实例,生产环境是进程复用,但仍需保证连接状态正确。
- 永远在调用
getDb前执行connect,确保数据库连接已建立。
内容的提问来源于stack exchange,提问作者Parshant Singh
相关产品推荐
相关产品推荐

