Next.js 14中间件中Mongoose模型调用报错:find不是函数
Next.js中间件中调用Mongoose模型报错:
User.find is not a function 问题重现
在Next.js 14.1中间件中执行以下代码查询用户:
let user: UserType[] | null = null; try { user = await findUser({id}); console.log("user", user); } catch (error: any) { throw new Error(error) }
出现如下错误:
⨯ unhandledRejection: Error: TypeError: ___WEBPACK_IMPORTED_MODULE_0__.User.find is not a function at addSiteToIntegration (webpack-internal:///(middleware)/./middleware.ts:51:15) at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
对应的Mongoose User Schema如下:
import mongoose from "mongoose"; const UserSchema = new mongoose.Schema({ userId: String, name: { type: String, required: true, }, email: String, phone: String, city: { type: String, default: "", }, apiKeys: [ { purpose: String, key: String, allowedOrigins: Array, }, ], customerRating: { type: Number, required: true, default: 0, }, businessName: String, businessRating: Number, bio: String, businessBio: String, businessDisplayName: String, isBetaUser: { type: Boolean, default: false, }, reviewWizardPresets: [ { id: String, text: String, onStars: String, }, ], blockList: [ { type: String, }, ], accesingWebsites: [{ url: String, description: String, name: String }], createdAt: { type: Date, required: true, default: () => Date.now(), }, updatedAt: Date, }); export default mongoose.models?.User || mongoose.model("User", UserSchema);
该问题仅在中间件中出现,Server Components或Route Handlers中运行正常,使用版本:Next.js 14.1、Mongoose 8.2.0、MongoDB 6.0.13(Atlas集群)。
问题原因
核心原因是Next.js中间件运行在Edge Runtime环境,而Mongoose主要为Node.js Runtime设计,两者存在以下关键差异:
- Edge Runtime不支持Node.js的部分核心API,Mongoose内部依赖的一些Node.js专属模块(如
fs、net)在Edge环境中无法正常工作 - 中间件的模块缓存机制与Node.js不同,
mongoose.models?.User的判断逻辑在Edge环境下可能无法正确复用已创建的模型,导致模型初始化不完整,find等方法未被挂载 - Mongoose 8.x对Edge Runtime的兼容性有限,官方尚未完全支持在Edge环境中使用完整的Mongoose功能
解决方案
方案1:将数据库查询逻辑移至Route Handler
中间件只负责路由拦截、权限校验等轻量逻辑,数据库查询通过调用内部Route Handler完成:
- 创建Route Handler(如
app/api/get-user/route.ts):
import { NextResponse } from "next/server"; import User from "@/models/User"; import connectDB from "@/lib/db"; export async function GET(request: Request) { await connectDB(); const { searchParams } = new URL(request.url); const id = searchParams.get("id"); if (!id) { return NextResponse.json({ error: "Missing user ID" }, { status: 400 }); } const user = await User.findOne({ _id: id }); return NextResponse.json(user); }
- 在中间件中调用该Handler:
try { const res = await fetch(`${process.env.NEXT_PUBLIC_APP_URL}/api/get-user?id=${id}`); const user = await res.json(); console.log("user", user); } catch (error: any) { throw new Error(error); }
方案2:使用MongoDB官方驱动替代Mongoose
MongoDB官方的mongodb驱动对Edge Runtime兼容性更好,直接使用驱动进行查询:
import { MongoClient, ObjectId } from "mongodb"; const client = new MongoClient(process.env.MONGODB_URI!); async function findUser({ id }: { id: string }) { await client.connect(); const db = client.db(process.env.MONGODB_DB_NAME); const user = await db.collection("users").findOne({ _id: new ObjectId(id) }); return user; }
方案3:调整Mongoose使用方式(有限兼容)
如果坚持使用Mongoose,需确保在中间件中手动初始化模型,避免依赖全局缓存:
import mongoose from "mongoose"; // 直接创建模型,不依赖mongoose.models缓存 const UserSchema = new mongoose.Schema({ /* 你的Schema定义 */ }); const User = mongoose.model("User", UserSchema); async function findUser({ id }: { id: string }) { await mongoose.connect(process.env.MONGODB_URI!); return User.find({ _id: id }); }
注意:这种方式可能仍存在Edge环境下的兼容性问题,建议优先使用前两种方案。
内容的提问来源于stack exchange,提问作者Ethan
相关产品推荐
相关产品推荐

