为啥我在第二次运行测试时在 Mongoose 中收到错误“一旦编译后无法覆盖模型”?
Posted
技术标签:
【中文标题】为啥我在第二次运行测试时在 Mongoose 中收到错误“一旦编译后无法覆盖模型”?【英文标题】:Why do I get error "Cannot overwrite model once compiled" in Mongoose when I run my test a second time?为什么我在第二次运行测试时在 Mongoose 中收到错误“一旦编译后无法覆盖模型”? 【发布时间】:2019-04-27 01:36:32 【问题描述】:我已阅读相关帖子:Cannot overwrite model once compiled Mongoose
问题是这些解决方案都没有帮助我解决我的问题。
我收到标题中的错误,我有以下设置:
文件夹结构:
我的模型如下所示:
论坛.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const topicGroupSchema = require("./topicGroups");
const forumSchema = new Schema(
title: String,
topicGroups: [topicGroupSchema]
)
const Forum = mongoose.model("forums", forumSchema);
module.exports = Forum;
topicGroups.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const topicGroupSchema = new Schema(
title: String,
// Todo: add topics
)
module.exports = topicGroupSchema;
我的 test_helper 和 saveForum_test.js 文件如下所示:
saveForum_test.js
const assert = require("assert");
const Forum = require("../model/forums")
describe("Creating records", () =>
it("can save a new forum", (done) =>
const forum = new Forum(
title: "CodeHUB"
)
forum.save()
.then(() =>
assert(forum.isNew)
done();
)
)
)
test_helper.js
const mongoose = require("mongoose");
mongoose.Promise = global.Promise;
before(done =>
mongoose.connect("mongodb://myuser:mypassword@ds221339.mlab.com:21339/clicker", useNewUrlParser: true );
mongoose.connection
.once("open", () => done())
.on("error", error =>
console.warn("error", error)
)
)
// FIXME: error when saved twice
beforeEach(done =>
console.log(mongoose.connection.collections.forums)
mongoose.connection.dropCollection("forums", () =>
done();
)
)
因此,当我使用 mocha 运行我的测试套件时,一切都按预期运行。 但是当我改变一些东西并再次运行它时,我得到了错误
OverwriteModelError: 编译后无法覆盖
forums
模型。
我将 mlab 与 mongoose 一起使用,而不是本地安装的 mongodb。也许它与此有关?我想不通,我检查了所有文件和导入等 10 次,找不到错误,你可以吗?
【问题讨论】:
更改什么并再次运行?这是您在问题中遗漏的内容,以及您引用的问题的答案中可能实际涵盖的内容,但您不理解它。请包括How to create a Minimal, Complete, and Verifiable example 中解释的可重现案例。我强调 Minimal 意味着足够的代码来显示问题。并且请不要将整个段落以粗体显示。它不会让您的问题变得更重要,而且人们能够阅读您的问题而无需对他们大喊大叫。 我想是因为问题可能出在我创建的任何文件中,所以我为每个示例都放入了 ocde,因为它们每个只有大约 20 行代码。但我很抱歉,并想努力让它变得更好。如何在 *** 上使用 mongoose 和 mlab 制作可验证的示例?你能给我一点提示从哪里开始吗?粗体字不是为了对你大喊大叫,它就像,“好吧,这是真正的问题”。我也发现了这一点,虽然我的应用程序并不复杂,但我可以联系起来:meta.***.com/questions/295634/… 【参考方案1】:我已经解决了这个问题。
原来问题在于我是如何运行我的测试套件的。
我在package.json
中的npm run test
命令执行了以下操作:
"test": "mocha --watch"
这是错误。我认为--watch
不会重新实例化所有内容,就像“热模块更换”一样。
我安装了nodemon
并像这样更改了我的测试脚本:
"test": "nodemon --exec \"mocha -R min\""
这可以确保重新运行整个文件并且不会出现错误。
另一个应该有效的相关帖子:mocha --watch and mongoose models
【讨论】:
【参考方案2】:我在导出模型时解决了这个问题。
return mongoose.models[modelName]
? mongoose.model(modelName)
: mongoose.model(modelName, modelSchema)
【讨论】:
这适用于热重载,尤其是 NextJS。 哈哈,绝招!谢谢:)【参考方案3】:还有另一个选项可以解决这个问题并继续使用 mocha --watch。
您可以使用类似这样的函数,而不需要模型,这样模型就不会被覆盖。
function loadModel(modelName, modelSchema)
return mongoose.models[modelName] // Check if the model exists
? mongoose.model(modelName) // If true, only retrieve it
: mongoose.model(modelName, modelSchema) // If false, define it
假设您有一个模型“用户”。您必须使用上述函数将其导出:
const userSchema = ...
module.exports = () => loadModel('User', userSchema)
现在,当您要导入模型时,您可以调用函数:
const User = require('../pathToTheModelLoaderFunction/user.js')()
【讨论】:
【参考方案4】:我建议您采用更简单的方法,即在测试运行后删除模型。
这里是:
after(() =>
delete mongoose.connection.models['MyModelName'];
);
您也可以在所有之前添加它,以确保您在没有现有模型的情况下开始所有测试。
Object.keys(mongoose.connection.models).forEach(modelName =>
delete mongoose.connection.models[modelName]
)
【讨论】:
以上是关于为啥我在第二次运行测试时在 Mongoose 中收到错误“一旦编译后无法覆盖模型”?的主要内容,如果未能解决你的问题,请参考以下文章
Redis hGet 方法在异步调用时在第二次调用时陷入死锁