为啥我在第二次运行测试时在 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 方法在异步调用时在第二次调用时陷入死锁

Mongoose 多个查询在第二次查询后返回

为啥按钮只有在第二次点击后才起作用? (反应)

为啥我的 ViewController 在第二次调用后才发布,iOS ARC?

为啥我的平移手势只能在第二次输入后识别事件?

量角器测试在第二次运行中因ng-reflect属性而失败