react-starter-kit: OverwriteModelError: Cannot overwrite `xxx` model once compiled.

Hi Guys. I have a problem. I understand what is going on, but I don’t know how it fixed. I’m using mongoose as common ORM instead sequelize. It work not bad. But when HMR started, I have seen error in my console. (node:29695) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): OverwriteModelError: Cannot overwrite Clientmodel once compiled. Mongoose doesn’t allow to define the model twice. When HMR tries to update server, it defines model twice. Can you save me?😃

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 21 (3 by maintainers)

Most upvoted comments

The way I did it is removing the model from mongoose’s models with

delete mongoose.connection.models['client'];

const clientSchema = mongoose.Schema({
  ...
});

export default mongoose.model('client', clientSchema);

Then you can register the model again through HMR or anything else.

@dpblh I fixed it like this:

export default (mongoose.models && mongoose.models.User
  ? mongoose.models.User
  : mongoose.model('User', userSchema));

This approach worked for me.

let UserSchema = null;

try { UserSchema = mongoose.model(‘User’, userSchema); } catch (e) { UserSchema = mongoose.model(‘User’); }

export default UserSchema;

Hi @dpblh Personally I don’t like magick like this, it will eat you in production. You have an options:

  • at first, split migrations to standalone script
  • at second, do not keen on magic 🎉 😉
  • and at last, use proper database or service which can save your paycheck 🙌

This is starter kit, not ready to use CMS, so you SHOULD make changes

Thank you very much @frenzzy, but it didn’t work for me. Because model have deep integration into server app. And I’d like to update my model in runtime. Or I don’t understand something:). I found a solution that helped me.

mongoose.js

import mongoose from 'mongoose';
import config from '../../config';

const connectionString = config.mongo.host
  .split(',')
  .map(host => `mongodb://${host}:${config.mongo.port}/${config.mongo.dbname}`)
  .join(',');

// todo workaround for HMR. It remove old model before added new ones
Object.keys(mongoose.connection.models).forEach(key => {
  delete mongoose.connection.models[key];
});

mongoose.connect(connectionString, config.mongo.options);
mongoose.Promise = global.Promise;

export default mongoose;

client.js

import mongoose from './mongoose';

const Client = mongoose.model(
  'Client',
  new mongoose.Schema({
    _id: { type: String, required: true },
    secret: { type: String, required: true },
  }),
);

export default Client;

So my model has always a new clean connection. I hope it’ll help somebody!

For me, i was requiring the model like this: var Book = .require(‘./models/Book.model’);

The name of the model is actually ‘book.model.js’ so the uppercase B caused the problem…

After i don the following all worked fine:

var Book = .require(‘./models/book.model’);

You can try to init model once inside tools/start.js script for the development mode Or even better you can add HMR for specific files:

import someFile from './some-file';

// ...

if (module.hot) {
  module.hot.accept('./some-file');
}

Read more: https://webpack.js.org/api/hot-module-replacement/

@pols63 You will always need split points. This stack is ready to be chopped to peaces, splitted, you must know when, it’s only your responsibility 😉 Is I said above, against dislikes: No magic cannot help you unboudlesly. Get bigger and break this stack to pieces. It should be easy if you are good architect 😉 Break out backend. If you can do it, you will learn why this stack is so awesome as starter…

If you want to overwrite the existing class for different collection using typescript then you have to inherit the existing class from different class.

export class User extends Typegoose{ @prop username?:string password?:string }

export class newUser extends User{ constructor() { super(); } }

export const UserModel = new User ().getModelForClass(User , { schemaOptions: { collection: “collection1” } });

export const newUserModel = new newUser ().getModelForClass(newUser , { schemaOptions: { collection: “collection2” } });