2

I have read related post: Cannot overwrite model once compiled Mongoose

Problem is neither of these solution's helped me with my problem.

I get the error in the title and I have following setup:

Folder Structure:

enter image description here

My models look like this:

forums.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;

My test_helper and saveForum_test.js files look like this:

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();
    })
})

So when I run my test suite with mocha, everything works as expected. But when I change something, and run it again, I get the error

OverwriteModelError: Cannot overwrite forums model once compiled.

I use mlab with mongoose and not a local installed mongodb. Maybe it has something todo with that? I can't figure it out, I checked all the files and imports etc. 10 times and can't find a mistake, can you ?

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
GeraltDieSocke
  • 1,524
  • 3
  • 20
  • 51
  • Change what and run it again? This is what you are missing in your question and what is likely actually covered in the answers to the question you reference but you are not understanding it. Please include a reproducible case as explained in [How to create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). I emphasize **Minimal** there meaning just enough code to show the problem. And please do not place whole paragraphs in bold. It does not make your question more important, and people are capable of reading your question without shouting at them. – Neil Lunn Nov 25 '18 at 01:19
  • I thought because the problem could be in any file I created, so I put in the ocde for every example, because they are just about 20 lines code each. But I apologize, and want to try to make it better. How can I make a verifiable example with mongoose and mlab on stackoverflow? Can you give me a little hint where to start? And the bold text was not for shouting at you, it was just like, "ok so here is the real question". Also I found this, and while my app is not complicated I can relate: https://meta.stackoverflow.com/questions/295634/stack-snippets-and-non-runnable-code – GeraltDieSocke Nov 25 '18 at 08:54

6 Answers6

10

I Solved with this, when I'm exporting my model.

return mongoose.models[modelName] 
    ? mongoose.model(modelName)
    : mongoose.model(modelName, modelSchema)
Tyler2P
  • 2,324
  • 26
  • 22
  • 31
jonathanlima
  • 159
  • 2
  • 9
6

I have solved the problem.

Turns out the problem was how I was running my test suite. My npm run test command in package.json did the following:

"test": "mocha --watch"

Here was the error. I think --watch doesn't reinstantiate everything and is just like "Hot Module Replacement".

I installed nodemon and changed my test script like this:

"test": "nodemon --exec \"mocha -R min\""

This makes sure to rerun the whole files and no error is showing up.

Another related post that should work: mocha --watch and mongoose models

GeraltDieSocke
  • 1,524
  • 3
  • 20
  • 51
3

I suggest you to have a simpler approach, which just consists in deleting the model after the test did run.

Here it is:

after(() => {
    delete mongoose.connection.models['MyModelName'];
});

You may also add it before all, in order to make sure you are starting all tests with no existing models.

Object.keys(mongoose.connection.models).forEach(modelName => {
    delete mongoose.connection.models[modelName]
})
aquiseb
  • 949
  • 8
  • 17
2

There is another option to solve this and keep using mocha --watch.

Instead of requiring the models, you can use a function like this one, so the model is no overwritten.

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
}

Imagine you have a model 'User'. You would have to export it using the above function:

const userSchema = {...}

module.exports = () => loadModel('User', userSchema)

Now, when you want to import the model, you do it calling the function:

const User = require('../pathToTheModelLoaderFunction/user.js')()
2

I also encountered this with HMR using Astro.js. It can be written short with:

return mongoose.models[modelName] ?? mongoose.model(modelName, modelSchema)

I am unsure if we have problems when the HMR updates because we changed the schema. So maybe the safer option would be:

if (mongoose.models[modelName] != null) {
    mongoose.deleteModel(modelName);
}
return mongoose.model(modelName, modelSchema);
panwauu
  • 47
  • 5
0

You can also try this elkport option so that the local server does not try to overwrite it helped me

export default mongoose.models['User'] || mongoose.model('User', userSchema);