Next.js13中Mongoose报MissingSchemaError:未注册post模型
解决Mongoose "Schema hasn't been registered for model 'post'" 错误
错误原因
- 连接上下文不兼容:当前使用原生
MongoClient连接数据库,但Mongoose需要依赖自身的连接机制管理模型与Schema,两者上下文不互通,导致Mongoose无法识别已注册的模型。 - 模型注册逻辑错误:
mongoose.model("post") || mongoose.model("post", PostSchema)的写法存在问题——第一次调用mongoose.model("post")时模型尚未注册,会直接抛出MissingSchemaError,无法执行后续的模型创建逻辑。
解决方案
1. 替换数据库连接方式为Mongoose原生连接
修改mongodb.ts文件内容,使用Mongoose官方的连接逻辑:
import mongoose from "mongoose"; if (!process.env.MONGODB_URI) { throw new Error('Invalid/Missing environment variable: "MONGODB_URI"'); } const uri = process.env.MONGODB_URI; let isConnected = false; async function connectDB() { if (isConnected) return; try { await mongoose.connect(uri); isConnected = true; console.log("MongoDB connected via Mongoose"); } catch (error) { throw new Error(`Failed to connect to MongoDB: ${error}`); } } export default connectDB;
2. 修正Post模型的注册逻辑
修改Post.ts(建议将文件名从Post.tsx改为Post.ts,因为这是数据模型而非React组件):
import mongoose from "mongoose"; import Joi from "joi"; type Post = { name: string; prompt: string; photo: string; }; const PostSchema = new mongoose.Schema({ name: { type: String, required: true }, prompt: { type: String, required: true }, photo: { type: String, required: true }, }); // 处理开发环境HMR导致的模型重复注册问题 const Post = mongoose.models.Post || mongoose.model<Post>("Post", PostSchema); function validatePost(data: Post) { const schema = Joi.object({ name: Joi.string().min(1).max(100).required(), prompt: Joi.string().min(2).required(), photo: Joi.string().required(), }); return schema.validate(data); } export { validatePost }; export default Post;
说明:
- 使用
mongoose.models.Post检查模型是否已存在,避免开发环境热重载时重复注册模型。 - 模型名采用首字母大写的
Post,Mongoose会自动映射到数据库的posts集合(符合MongoDB命名规范)。
3. 更新API文件,确保先完成Mongoose连接
修改API文件中的连接逻辑,必须等待Mongoose连接完成后再操作模型:
import type { NextApiRequest, NextApiResponse } from "next"; import connectDB from "@/lib/mongodb/mongodb"; import { v2 as cloudinary } from "cloudinary"; import Post from "@/lib/mongodb/models/post"; import { validatePost } from "@/lib/mongodb/models/post"; cloudinary.config({ cloud_name: process.env.CLOUDINARY_CLOUD_NAME, api_key: process.env.CLOUDINARY_API_KEY, api_secret: process.env.CLOUDINARY_API_SECRET, }); export const config = { api: { bodyParser: { sizeLimit: "50mb", }, responseLimit: false, }, }; export default async function handler( req: NextApiRequest, res: NextApiResponse ) { // 先等待Mongoose连接完成 await connectDB(); if (req.method === "GET") { try { const posts = await Post.find({}); res.status(200).json({ success: true, data: posts }); } catch (err) { res.status(500).json({ success: false, message: "Fetching posts failed, please try again", }); } } else if (req.method === "POST") { try { const { error } = validatePost(req.body); if (error) return res.status(400).send(error.details[0].message); const { name, prompt, photo } = req.body; const photoUrl = await cloudinary.uploader.upload(photo); const post = new Post({ name, prompt, photo: photoUrl.url, }); const newPost = await post.save(); res.status(200).json({ success: true, data: newPost }); } catch (err) { res.status(500).json({ success: false, message: "Unable to create a post, please try again", }); } } else { res.status(405).json({ success: false, message: "Method not allowed" }); } }
额外注意事项
- 确保
MONGODB_URI环境变量格式正确,Mongoose支持与原生MongoClient相同的连接字符串格式。 - 开发环境中Next.js的热重载(HMR)可能导致模型重复注册,因此必须保留
mongoose.models.Post的检查逻辑。
内容的提问来源于stack exchange,提问作者Jahanzaib Tayyab
相关产品推荐
相关产品推荐

