Mongoose/NextJS - 模型未定义/编译后无法覆盖模型
Posted
技术标签:
【中文标题】Mongoose/NextJS - 模型未定义/编译后无法覆盖模型【英文标题】:Mongoose/NextJS - Model is not defined / Cannot overwrite model once compiled 【发布时间】:2020-10-07 22:29:14 【问题描述】:TL;DR EDIT:如果您来自 Google,这就是解决方案:
module.exports = mongoose.models.User || mongoose.model("User", UserSchema);
对于非 TL;DR 答案,请检查接受的答案。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
p>我正在开发一个 NextJS 网站,在后端我使用的是 Mongoose 和 Express。每当我使用 signUp 功能时,我都会在后端收到此错误:
"name":"Test","hostname":"DESKTOP-K75DG72","pid":7072,"level":40,"route":"/api/v1/signup","method":"POST","errorMessage":"UserModel is not defined","msg":"","time":"2020-06-17T23:51:34.566Z","v":0
我怀疑这个错误是因为我在其他控制器中使用了 UserModel。直到我制作了一个新的控制器,这个错误才发生。所以我的问题是,我该如何解决这个问题/如何在不同的控制器/中间件中使用相同的模型?
我认为这个问题与 node.js - Cannot overwrite model once compiled Mongoose 这个帖子有关,我之前收到了这个错误,但不知何故设法修复了它。
编辑:错误在于模型/User.js,在预保存中间件中,UserModel 未在级别定义,我如何验证用户是否已使用该用户名存在,如果存在,则拒绝新文件?
在 controllers/RegisterLogin.js [发生错误的地方]
const UserModel = require("../models/User");
// More packages...
async function signUp(req, res)
try
const value = await signUpSchema.validateAsync(req.body);
const response = await axios(
method: "POST",
url: "https://hcaptcha.com/siteverify",
data: qs.stringify(
response: value.token,
secret: process.env.HCAPTCHA,
),
headers:
"content-type": "application/x-www-form-urlencoded;charset=utf-8",
,
);
if (!response.data.success)
throw new Error(errorHandler.errors.HCAPTCHA_EXPIRED);
const hashPassword = await new Promise((res, rej) =>
bcrypt.hash(
value.password,
parseInt(process.env.SALTNUMBER, 10),
function (err, hash)
if (err) rej(err);
res(hash);
);
);
await UserModel.create(
userName: value.username,
userPassword: hashPassword,
userBanned: false,
userType: "regular",
registeredIP: req.ip || "N/A",
lastLoginIP: req.ip || "N/A",
);
return res.status(200).json(
success: true,
details:
"Your user has been created successfully! Redirecting in 6 seconds",
);
catch (err)
const message = err;
if (errorHandler.isUnknownError(message))
logger.warn(
route: "/api/v1/signup",
method: "POST",
errorMessage: message,
);
return res.status(200).json(
success: false,
details: errorHandler.parseError(message),
);
module.exports = signUp ;
在 controllers/Profile.js [如果我在这里使用 UserModel,它会破坏一切]
const UserModel = require("../models/User");
//plus other packages...
async function changePassword(req, res)
try
const value = await passwordChangeSchema.validateAsync(req.body);
const username = await new Promise((res, rej) =>
jwt.verify(value.token, process.env.PRIVATE_JWT, function (err, decoded)
if (err) rej(err);
res(decoded.username);
);
);
const userLookup = await UserModel.find( userName: username );
if (userLookup == null || userLookup.length == 0)
throw new Error(errorHandler.errors.BAD_TOKEN_PROFILE);
const userLookupHash = userLookup[0].userPassword;
try
// We wrap this inside a try/catch because the rej() doesnt reach block-level
await new Promise((res, rej) =>
bcrypt.compare(value.currentPassword, userLookupHash, function (
err,
result
)
if (err)
rej(errorHandler.errors.BAD_CURRENT_PASSWORD);
if (result == true)
res();
else
rej(errorHandler.errors.BAD_CURRENT_PASSWORD);
);
);
catch (err)
throw new Error(err);
const hashPassword = await new Promise((res, rej) =>
bcrypt.hash(
value.newPassword,
parseInt(process.env.SALTNUMBER, 10),
function (err, hash)
if (err) rej(err);
res(hash);
);
);
await UserModel.findOneAndUpdate(
userName: username ,
userPassword: hashPassword
);
return res.status(200).json(
success: true,
details: "Your password has been updated successfully",
);
catch (err)
const message = err;
if (errorHandler.isUnknownError(message))
logger.warn(
route: "/api/v1/changepassword",
method: "POST",
errorMessage: message,
);
return res.status(200).json(
success: false,
details: errorHandler.parseError(message),
);
在 models/User.js
const mongoose = require("mongoose");
const errorHandler = require("../helpers/errorHandler");
const Schema = mongoose.Schema;
const UserSchema = new Schema(
userName: String,
userPassword: String,
userBanned: Boolean,
userType: String,
registeredDate: type: Date, default: Date.now ,
registeredIP: String,
lastLoginDate: type: Date, default: Date.now ,
lastLoginIP: String,
);
UserSchema.pre("save", async function ()
const userExists = await UserModel.find(
userName: this.get("userName"),
)
.lean()
.exec();
if (userExists.length > 0)
throw new Error(errorHandler.errors.REGISTER_USERNAME_EXISTS);
);
module.exports = mongoose.model("User", UserSchema);
【问题讨论】:
是否有errorHandler
require()
任何控制器?
@thammada 不,errorHandler 有一个对象“errors”,它是一个友好错误列表,可以显示在前端,同时记录严重错误。 errorHandler 没有任何 require()
models/User.js
是否还有其他 require()
s?
@thammada 不,只有 errorHandler 和 mongoose 本身。
@thammada 设法修复它,没有任何循环依赖,谢谢!
【参考方案1】:
我已经设法修复它。这里有两个问题。
1) “UserModel”变量在预中间件中不存在。通过实例化 this.constructor 解决,这显然解决了问题(需要进一步测试)
2) NextJS 构建所有东西显然存在问题,每当我使用 UserModel 中的任何函数时,它似乎都在尝试创建一个新模型。这是固定导出已创建的模型
const mongoose = require("mongoose");
const errorHandler = require("../helpers/errorHandler");
const Schema = mongoose.Schema;
const UserSchema = new Schema(
userName: String,
userPassword: String,
userBanned: Boolean,
userType: String,
registeredDate: type: Date, default: Date.now ,
registeredIP: String,
lastLoginDate: type: Date, default: Date.now ,
lastLoginIP: String,
);
UserSchema.pre("save", async function ()
try
const User = this.constructor;
const userExists = await User.find(
userName: this.get("userName"),
)
.lean()
.exec();
if (userExists.length > 0)
throw new Error(errorHandler.errors.REGISTER_USERNAME_EXISTS);
catch (err)
throw new Error(errorHandler.errors.REGISTER_USERNAME_EXISTS);
);
module.exports = mongoose.models.User || mongoose.model("User", UserSchema);
【讨论】:
谢谢,这解决了我一直困扰我的一个错误。 你是我的主和救世主,真是令人沮丧。最后一行为我解决了它 最后一行正是我所需要的:module.exports = mongoose.models.User || mongoose.model("User", UserSchema);
为我节省了很多时间。谢谢!
使用 ES6 import export 和 ts 这解决了我的问题:const UserModel = models.User || model<IUser>('User', UserSchema); export default UserModel;
以上是关于Mongoose/NextJS - 模型未定义/编译后无法覆盖模型的主要内容,如果未能解决你的问题,请参考以下文章
使用新模型和保护的 Laravel 身份验证失败:未定义索引:模型