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

Created on 2 Oct 2017  Â·  18Comments  Â·  Source: kriasoft/react-starter-kit

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 overwriteClientmodel 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?:)

Most helpful comment

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.

All 18 comments

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/

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!

Maybe

/* server.js */
import mongoose from './mongoose';

// ...

if (model.hot) {
  module.hot.accept();
  module.hot.dispose(() => {
    mongoose.disconnect();
  });
  // ...
}

It doesn't work for me :(
Because the model is initialized before.

/* server.js */
import mongoose from './mongoose';

// somewhere here the model is initialized

if (model.hot) {
  module.hot.accept();
  module.hot.dispose(() => {
    mongoose.disconnect();
  });
  // ...
}

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 :tada: :wink:
  • and at last, use proper database or service which can save your paycheck :raised_hands:

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

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.

Hi @langpavel
I really agree with you

  1. It should never be used in production
  2. Undocumented features’s bed way)
  3. I don’t think)
    Only this way worked
    Late I’ll fix it

@dpblh I fixed it like this:

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

@kppf that won't work if you change your schema and save if you use Hot Module Replacement though

@tgdn Yes. That doesn't update the schema using Hot Module Replacement. Your approach (delete/create/export) seems better.

This approach worked for me.

let UserSchema = null;

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

export default UserSchema;

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

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');

In my case, I need change the structure of schemas and requires code without restart the service.

@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…

Thanks for the answer. You right. But, I still think Mongoose must give the option to redefine a model. Many developers search the method for many reason, that must to say that option help us. In my case, our system must not be restarted because many collaborators and industrial machines are connected and we can't wait to night for updates.

Sure @pols63 some models are more smooth than others.
If you evolve you must be prepared for this steps. Better soon then later :-)
You should evolve your model faster than your customers ;-) So you will not be surprised…
BTW RSK is opinionated stack with much of different use cases, so no prediction here, sorry, we all guess :-D
Don't take me bad, but you may look under the hood and target on your needs.
Cheers

Ok. I understand. But not all is one hundred percent predictible. Not always we can anticipate, proof of that is that Mongoose hasn't option for update models at runtime, like many customers want. I insist, let us choice update or not in runtime.

Was this page helpful?
0 / 5 - 0 ratings