NextJS 13搭配Mongoose偶现OverwriteModelError问题求助
问题:Next.js 13.4.12 + Mongoose 7.4.2 开发环境下偶现OverwriteModelError
使用Next.js 13.4.12搭配Mongoose 7.4.2开发,浏览器调用RestAPI时偶尔触发OverwriteModelError,提示无法覆盖已编译的useranswer模型。仅在npm run dev模式下出现,npm run build+npm run start生产模式无此问题,且错误并非首次加载出现,需多次刷新页面才会触发。
相关代码片段
1. Difficulty.ts 数据模型定义
import mongoose, { Schema, model, Types } from "mongoose"; const difficultySchema = new Schema({ name: { type: String, required: true, }, value: { type: Number, required: true, }, }); export default mongoose.models.Difficulty || model("difficulty", difficultySchema);
2. dbConnect.ts 数据库连接代码
import mongoose, { connect } from "mongoose"; let cached: undefined | Promise<void>; export default () => { if (mongoose.connections && mongoose.connections[0].readyState) return Promise.resolve(); if (!cached) { cached = connect(process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/quiz') .then(() => console.log("connected to database.")) .catch((err) => console.log("could not connect to database", err)); } return cached; }
3. difficulty/page.tsx 页面组件
"use client"; import React from 'react' import { DataTable } from "primereact/datatable" import { Column } from "primereact/column" import { useQuery } from '@tanstack/react-query'; import Link from 'next/link'; export default function Difficulty() { const { data: difficultyValues, status: dataFetchStatus, isLoading: isDataLoading } = useQuery({ queryKey: ["difficulty"], queryFn: async () => { const res = await fetch(`/api/difficulty`, { cache: "no-cache" }); return res.json(); } }); return ( <> <DataTable value={difficultyValues} loading={isDataLoading}> <Column field='name' header="Name"></Column> </DataTable> <Link href="/">Home</Link> </> ) }
4. api/difficulty/route.ts 接口代码
import Difficulty from "@/app/api/models/Difficulty"; import connection from "@/app/lib/dbConnect"; import { NextResponse } from "next/server"; export async function GET() { await connection(); let result = await Difficulty.find({}); return NextResponse.json(result); }
5. UserAnswer.ts 数据模型定义(错误关联但未直接使用)
import mongoose, { Schema, model, Types } from "mongoose"; const userAnswerSchema = new Schema({ question_answer_id: { type: Types.ObjectId, required: true, ref: 'questionanswer' }, recorded_time: { type: Date, required: false, }, user_id: { type: Types.ObjectId, required: true, ref: 'user' }, thinkingtime: { type: Number, required: true, }, }); export default mongoose.models.UserAnswer || model("useranswer", userAnswerSchema);;
完整错误信息
[31merror[39m OverwriteModelError: Cannot overwrite `useranswer` model once compiled. at Mongoose.model (E:\work\integrity\Homeworks\homework4nextjs\node_modules\mongoose\lib\index.js:563:13) at eval (webpack-internal:///(rsc)/./app/api/models/UserAnswer.ts:28:184) at (rsc)/./app/api/models/UserAnswer.ts (E:\work\integrity\Homeworks\homework4nextjs\next\server\app\api\question\route.js:82:1) at __webpack_require__ (E:\work\integrity\Homeworks\homework4nextjs\next\server\webpack-runtime.js:33:42) at eval (webpack-internal:///(rsc)/./app/api/models/QuestionAnswer.ts:7:69) at (rsc)/./app/api/models/QuestionAnswer.ts (E:\work\integrity\Homeworks\homework4nextjs\next\server\app\api\question\route.js:72:1) at __webpack_require__ (E:\work\integrity\Homeworks\homework4nextjs\next\server\webpack-runtime.js:33:42) at eval (webpack-internal:///(rsc)/./app/api/models/Question.ts:7:73) at (rsc)/./app/api/models/Question.ts (E:\work\integrity\Homeworks\homework4nextjs\next\server\app\api\question\route.js:62:1) at __webpack_require__ (E:\work\integrity\Homeworks\homework4nextjs\next\server\webpack-runtime.js:33:42) at eval (webpack-internal:///(rsc)/./app/api/question/route.ts:5:82) at (rsc)/./app/api/question/route.ts (E:\work\integrity\Homeworks\homework4nextjs\next\server\app\api\question\route.js:92:1) at __webpack_require__ (E:\work\integrity\Homeworks\homework4nextjs\next\server\webpack-runtime.js:33:42) at eval (webpack-internal:///(rsc)/./node_modules/next/dist/build/webpack/loaders/next-app-loader.js?name=app%2Fapi%2Fquestion%2Froute&page=%2Fapi%2Fquestion%2Froute&appPaths=&pagePath=private-next-app-dir%2Fapi%2Fquestion%2Froute.ts&appDir=E%3A%5Cwork%5Cintegrity%5CHomeworks%5Chomework4nextjs%5Capp&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&rootDir=E%3A%5Cwork%5Cintegrity%5CHomeworks%5Chomework4nextjs&isDev=true&tsconfigPath=tsconfig.json&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D!:16:126) at (rsc)/./node_modules/next/dist/build/webpack/loaders/next-app-loader.js?name=app%2Fapi%2Fquestion%2Froute&page=%2Fapi%2Fquestion%2Froute&appPaths=&pagePath=private-next-app-dir%2Fapi%2Fquestion%2Froute.ts&appDir=E%3A%5Cwork%5Cintegrity%5CHomeworks%5Chomework4nextjs%5Capp&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&rootDir=E%3A%5Cwork%5Cintegrity%5CHomeworks%5Chomework4nextjs&isDev=true&tsconfigPath=tsconfig.json&basePath=&assetPrefix=&nextConfigOutput=&preferredRegion=&middlewareConfig=e30%3D! (E:\work\integrity\Homeworks\homework4nextjs\next\server\app\api\question\route.js:42:1) at __webpack_require__ (E:\work\integrity\Homeworks\homework4nextjs\next\server\webpack-runtime.js:33:42) at __webpack_exec__ (E:\work\integrity\Homeworks\homework4nextjs\next\server\app\api\question\route.js:692:39) at E:\work\integrity\Homeworks\homework4nextjs\next\server\app\api\question\route.js:693:28 at Object. (E:\work\integrity\Homeworks\homework4nextjs\next\server\app\api\question\route.js:696:3) at Module._compile (e:\work\integrity\Homeworks\homework4nextjs\lib\internal\modules\cjs\loader.js:1255:14) at Module._extensions..js (e:\work\integrity\Homeworks\homework4nextjs\lib\internal\modules\cjs\loader.js:1309:10) at Module.load (e:\work\integrity\Homeworks\homework4nextjs\lib\internal\modules\cjs\loader.js:1113:32) at Module._load (e:\work\integrity\Homeworks\homework4nextjs\lib\internal\modules\cjs\loader.js:960:12) at Module.require (e:\work\integrity\Homeworks\homework4nextjs\lib\internal\modules\cjs\loader.js:1137:19) at require (e:\work\integrity\Homeworks\homework4nextjs\lib\internal\modules\helpers.js:121:18) at requirePage (e:\work\integrity\Homeworks\homework4nextjs\node_modules\next\dist\server\require.js:112:75) at e:\work\integrity\Homeworks\homework4nextjs\node_modules\next\dist\server\load-components.js:80:84 at process.processTicksAndRejections (e:\work\integrity\Homeworks\homework4nextjs\lib\internal\process\task_queues.js:95:5) at async loadComponentsImpl (e:\work\integrity\Homeworks\homework4nextjs\node_modules\next\dist\server\load-components.js:80:26) at async DevServer.findPageComponentsImpl (E:\work\integrity\Homeworks\homework4nextjs\node_modules\next\dist\server\next-server.js:434:36) {name: 'OverwriteModelError', digest: undefined, stack: 'OverwriteModelError: Cannot overwrite `useran…dules\next\dist\server\next-server.js:434:36)', message: 'Cannot overwrite `useranswer` model once compiled.', Symbol(NextjsError): 'server'}
解决方案
核心原因
开发环境下Next.js的热重载机制会重复加载模块,而模型定义中检查已注册模型的键名与实际注册名称不匹配:
- 注册
UserAnswer模型时使用model("useranswer", userAnswerSchema),模型名称为小写的useranswer - 但检查时用了
mongoose.models.UserAnswer(驼峰命名),该键不存在于mongoose.models中,导致每次热重载都会重新调用model()方法,尝试覆盖已编译的模型,触发错误。 - 同样问题也存在于
Difficulty.ts中,只是暂时未触发明显错误。
修复步骤
修改所有模型文件,确保检查已注册模型时使用的键名与model()方法中传入的名称完全一致:
修改 UserAnswer.ts
import mongoose, { Schema, model, Types } from "mongoose"; const userAnswerSchema = new Schema({ question_answer_id: { type: Types.ObjectId, required: true, ref: 'questionanswer' }, recorded_time: { type: Date, required: false, }, user_id: { type: Types.ObjectId, required: true, ref: 'user' }, thinkingtime: { type: Number, required: true, }, }); // 改为与注册名称一致的小写键名 export default mongoose.models.useranswer || model("useranswer", userAnswerSchema);
修改 Difficulty.ts
import mongoose, { Schema, model, Types } from "mongoose"; const difficultySchema = new Schema({ name: { type: String, required: true, }, value: { type: Number, required: true, }, }); // 改为与注册名称一致的小写键名 export default mongoose.models.difficulty || model("difficulty", difficultySchema);
额外说明
生产环境下不会出现该问题,是因为npm run build会将代码打包为静态文件,模块只会加载一次,不会触发重复注册模型的情况。而开发环境的热重载会多次加载模块,暴露了键名不匹配的问题。
内容的提问来源于stack exchange,提问作者Papp Zoltán
相关产品推荐
相关产品推荐

