Mongoose: corrigindo "Cannot overwrite 'Model' model once compiled"

Mongoose: corrigindo "Cannot overwrite 'Model' model once compiled"

Tulio Faria
Tulio Faria3 de outubro de 2016
Durante o desenvolvimento de um protótipo aqui na empresa, eu me deparei com uma situação bem interessante no Mongoose. Por algum motivo, comecei a receber o seguinte erro: OverwriteModelError: Cannot overwrite `User` model once compiled.

C:\\Arquivos\\devpleno\\conteudos\\mongoose-problem-windows\\node\_modules\\mongoose\\lib\\index.js:361 throw new mongoose.Error.OverwriteModelError(name); ^ OverwriteModelError: Cannot overwrite \`User\` model once compiled. at Mongoose.model (C:\\Arquivos\\devpleno\\conteudos\\mongoose-problem-windows\\node\_modules\\mongoose\\lib\\index.js:361:13) at Object.<anonymous> (C:\\Arquivos\\devpleno\\conteudos\\mongoose-problem-windows\\User.js:8:27) at Module.\_compile (module.js:413:34) at Object.Module.\_extensions..js (module.js:422:10) at Module.load (module.js:357:32) at Function.Module.\_load (module.js:314:12) at Module.require (module.js:367:17) at require (internal/module.js:16:19) at Object.<anonymous> (C:\\Arquivos\\devpleno\\conteudos\\mongoose-problem-windows\\postsController.js:1:74) at Module.\_compile (module.js:413:34) at Object.Module.\_extensions..js (module.js:422:10) at Module.load (module.js:357:32) at Function.Module.\_load (module.js:314:12) at Module.require (module.js:367:17) at require (internal/module.js:16:19) at Object.<anonymous> (C:\\Arquivos\\devpleno\\conteudos\\mongoose-problem-windows\\index.js:6:1)

O que me intrigou muito foi que sempre utilizei o Mongoose praticamente da mesma forma. O exemplo que gerou este erro é este aqui:

var mongoose = require('mongoose') mongoose.connect('mongodb://localhost/mongoose-problem') require('./usersController.js') require('./postsController.js')

O model User:

var mongoose = require('mongoose') var userSchema = mongoose.Schema({ email: String, password: String }) module.exports = mongoose.model('User', userSchema)

E os 2 controllers, que simulam a utilização deste model:

var User = require('./user') // restante do código do controller var Post = require('./User') // restante do código do controller

Bom, analisando o erro novamente, podemos notar que por algum motivo ao executar o código, o módulo onde está o model está sendo instanciado mais de uma vez. E isso acarreta em setar o schema duas vezes, gerando assim este erro.
Se analisarmos como está sendo dado o require em cada controller, vamos notar que um deles está como user e no outro User. No Windows, se tentarmos abrir um arquivo User.js ou user.js, ambos irão apontar para o mesmo local (que foi o que aconteceu aqui).
Porém, o nodejs gerencia os módulos em si de maneira case-sensitive. Então se fizermos: require('./User') e require('./user'), o nodejs vai tentar registrar 2x. O que duplica o registro do schema User no mongoose.
No Linux/Mac isso não aconteceria, pois bem antes de esse erro "pipocar", o node já iria gritar dizendo que o módulo User.js não existe. E ficaria bem mais simples de encontrar o erro.

Outros efeitos colaterais deste problema:

Se por algum motivo, tivéssemos um trecho de código que não possuísse a restrição do mongoose+schema (de não poder ser registrado mais de uma vez). Este código seria executado 2x no Windows (pois o node registraria 2x o módulo).
Isso poderia gerar um bug/efeito colateral que aconteceria somente no Windows. E o código quebraria quando fosse colocado em produção no Linux. O ideal então é manter um padrão, e chamar no require da mesma forma que o arquivo foi salvo. Evitando assim, muita dor de cabeça.
Curta o DevPleno no Facebook, se inscreva no canal no YouTube e cadastre seu e-mail para não perder as atualizações. Abraço!
Tulio Faria
Autor
Tulio Faria3 de outubro de 2016

Últimas do Blog