No se puede sobrescribir el modelo una vez compilado Mongoose

109

No estoy seguro de lo que estoy haciendo mal, aquí está mi check.js

var db = mongoose.createConnection('localhost', 'event-db');
db.on('error', console.error.bind(console, 'connection error:'));

var a1= db.once('open',function(){
var user = mongoose.model('users',{ 
       name:String,
       email:String,
       password:String,
       phone:Number,
      _enabled:Boolean
     });

user.find({},{},function (err, users) {
    mongoose.connection.close();
    console.log("Username supplied"+username);
    //doSomethingHere })
    });

y aquí está mi insert.js

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/event-db')

var user = mongoose.model('users',{
     name:String,
     email:String,
     password: String,
     phone:Number,
     _enabled:Boolean
   });

var new_user = new user({
     name:req.body.name,
     email: req.body.email,
     password: req.body.password,
     phone: req.body.phone,
     _enabled:false
   });

new_user.save(function(err){
    if(err) console.log(err); 
   });

Siempre que intento ejecutar check.js, aparece este error

No se puede sobrescribir el modelo de 'usuarios' una vez compilado .

Entiendo que este error se debe a que el esquema no coincide, pero no puedo ver dónde está sucediendo. Soy bastante nuevo en mangosta y nodeJS.

Esto es lo que obtengo de la interfaz de cliente de mi MongoDB:

MongoDB shell version: 2.4.6 connecting to: test 
> use event-db 
  switched to db event-db 
> db.users.find() 
  { "_id" : ObjectId("52457d8718f83293205aaa95"), 
    "name" : "MyName", 
    "email" : "[email protected]", 
    "password" : "myPassword", 
    "phone" : 900001123, 
    "_enable" : true 
  } 
>
Anathema.Imbuido
fuente
Esto es lo que obtengo de la interfaz de cliente de mi MongoDB: Versión de shell de MongoDB: 2.4.6 conectando a: test> use event-db cambiado a db event-db> db.users.find () {"_id": ObjectId ("52457d8718f83293205aaa95"), "name": "MyName", "email": "[email protected]", "password": "myPassword", "phone": 900001123, "_enable": true}>
Anathema Imbuido el

Respuestas:

110

El error se produce porque ya tiene un esquema definido y luego está definiendo el esquema nuevamente. Generalmente, lo que debe hacer es crear una instancia del esquema una vez y luego hacer que un objeto global lo llame cuando lo necesite.

Por ejemplo:

user_model.js

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var userSchema = new Schema({
   name:String,
   email:String,
   password:String,
   phone:Number,
   _enabled:Boolean
});
module.exports = mongoose.model('users', userSchema);          

check.js

var mongoose = require('mongoose');
var User = require('./user_model.js');

var db = mongoose.createConnection('localhost', 'event-db');
db.on('error', console.error.bind(console, 'connection error:'));
var a1= db.once('open',function(){
  User.find({},{},function (err, users) {
    mongoose.connection.close();
    console.log("Username supplied"+username);
    //doSomethingHere 
  })
});

insert.js

var mongoose = require('mongoose');
var User = require('./user_model.js');

mongoose.connect('mongodb://localhost/event-db');
var new_user = new User({
    name:req.body.name
  , email: req.body.email
  , password: req.body.password
  , phone: req.body.phone
  , _enabled:false 
});
new_user.save(function(err){
  if(err) console.log(err); 
});
thtsigma
fuente
69
Evite exportar / requerir modelos: si alguno tiene refs para otros modelos, esto puede llevar a una pesadilla de dependencia. Utilizar en var User = mongoose.model('user')lugar de require.
wprl
1
De hecho, puede ser útil cambiar un esquema después de definirlo para probar el código de migración del esquema.
Igor Soarez
1
@wprl, ¿puedes explicarlo más? ¿Por qué requerirlo crearía un problema?
varuog
Esta respuesta es engañosa. El hecho es que si solo hay una instancia de servidor mongoDB y más bases de datos, si define en otra aplicación la base de datos que ya está en uso, entonces tiene ese error. Así de simple
Carmine Tambascia
174

Entonces, otra razón por la que puede obtener este error es si usa el mismo modelo en diferentes archivos pero su requireruta tiene un caso diferente. Por ejemplo en mi situación tuve:

require('./models/User')en un archivo y luego en otro archivo donde necesitaba acceder al modelo de usuario que tenía require('./models/user').

Supongo que la búsqueda de módulos y mangosta lo trata como un archivo diferente. Una vez que me aseguré de que el caso coincidiera en ambos, ya no fue un problema.

Jonnie
fuente
7
Ese es un problema muy complicado, creo que es específico del sistema operativo (debería ocurrir solo en Mac y Windows, ya que el FS ignora el caso). Tuve este problema, pero afortunadamente vi tu respuesta :) ¡Muchas gracias Jonnie!
Miroslav Nedyalkov
6
este problema ocurre en mi sistema OS X.
lutaoact
Nunca podría haberlo pensado, ¡al menos no intuitivamente! gracias
Naveen Attri
Ese era totalmente mi problema. Nunca pensé que tener un nombre en mayúsculas causaría algún problema.
Sandip Subedi
Esto fue lo mismo para mí. Todos saludan a OS X y su sistema de archivos (no distingue entre mayúsculas y minúsculas de forma predeterminada)
mithril_knight
50

Tuve este problema durante la prueba unitaria.

La primera vez que llama a la función de creación de modelo, mangosta almacena el modelo bajo la clave que usted proporciona (por ejemplo, 'usuarios'). Si llama a la función de creación del modelo con la misma clave más de una vez, la mangosta no le permitirá sobrescribir el modelo existente.

Puedes comprobar si el modelo ya existe en mangosta con:

let users = mongoose.model('users')

Esto arrojará un error si el modelo no existe, por lo que puede envolverlo en un intento / captura para obtener el modelo o crearlo:

let users
try {
  users = mongoose.model('users')
} catch (error) {
  users = mongoose.model('users', <UsersSchema...>)
}
BJ Anderson
fuente
1
+1 Estaba teniendo el mismo problema en el que necesitaba configurar alguna configuración para un complemento antes de poder definir mi esquema. Esto no funcionó bien con el moca y al final me di por vencido y seguí este enfoque de intento de captura
Victor Parmar
Estoy usando lo mismo pero al revés, eso es perverso:try exports.getModel = ()-> mongoose.model('User', userSchema) catch err exports.getModel = ()-> mongoose.model('User')
Andi Giga
Gracias buen señor, desperdició más de 5 horas en este problema. Estaba trabajando con servidor sin servidor a diferencia del servidor de nodo al que estoy acostumbrado.
mxdi9i7
43

Tuve este problema mientras 'miraba' las pruebas. Cuando se editaron las pruebas, el reloj volvió a ejecutar las pruebas, pero fallaron debido a esta misma razón.

Lo arreglé verificando si el modelo existe y luego lo usé, de lo contrario, créelo.

import mongoose from 'mongoose';
import user from './schemas/user';

export const User = mongoose.models.User || mongoose.model('User', user);
ZephDavies
fuente
Esto funcionó para mí. Había cambiado el module.export = Usera export defaults User. También tuve refsque User de otros modelos. No estoy seguro de por qué el cambio de module.exportsa export defaulttrajo este problema. Sin embargo, esta respuesta parece haberlo solucionado.
runios
3
lo malo mongoose.modelsno existe, al menos en versiones recientes
Pedro Luz
1
Tuve el mismo problema, pero lo solucioné borrando todos los modelos antes de todas las pruebas:for (let model in mongoose.models) delete mongoose.models[model]
E. Sundin
Mi script de prueba se ve así: "test": "NODE_ENV=test mocha --file mocha.config.js --watch"y en ese archivo js de configuración tengo un before()y after()para manejar la configuración y el desmontaje. @ E.Sundin proporcionó la solución perfecta aquí, y funciona de maravilla. ¡Gracias!
Brandon Aaskov
21

He estado experimentando este problema y no fue por las definiciones del esquema, sino por el modo fuera de línea sin servidor; simplemente logré resolverlo con esto:

serverless offline --skipCacheInvalidation

Que se menciona aquí https://github.com/dherault/serverless-offline/issues/258

Con suerte, eso ayudará a alguien más que esté construyendo su proyecto en modo sin servidor y sin conexión.

munyah
fuente
2
Muy útil. Gracias.
Thanh Truong
2
Me pareció molesto omitir la invalidación de caché, las recargas constantes, en cambio, esto funcionamodule.exports = mongoose.models.Users || mongoose.model('Users', UsersSchema);
ask_io
me
alegraste el
¡Un millón de gracias!
AndyFaizan
Esto fue muy útil. ¡Gracias!
ifiok
20

Si está utilizando Serverless sin conexión y no desea utilizarlo --skipCacheInvalidation, puede utilizar:

module.exports = mongoose.models.Users || mongoose.model('Users', UsersSchema);
Julian
fuente
También debe usar esto si está importando un modelo dentro de otro, incluso con--skipCacheInvalidation
Powderham
1
Esta es la respuesta exacta que estaba buscando, para usar en Next.js. ¡Ojalá esto estuviera más arriba en la página!
Brendan Nee
18

Si llegó aquí, es posible que haya tenido el mismo problema que yo. Mi problema fue que estaba definiendo otro modelo con el mismo nombre . Llamé a mi galería y mi modelo de archivo "Archivo". ¡Maldita sea, copia y pega!

James Harrington
fuente
11

Esto me pasó a mí cuando escribo así:

import User from '../myuser/User.js';

Sin embargo, la verdadera ruta es '../myUser/User.js'

ip192
fuente
La combinación de casos de rutas de esquema al importar parece causar este problema; verifique que todos los archivos que importan el esquema utilicen el mismo caso.
Andrew Cupper
¡esto nos salvó! Tenemos la sensación de que esto podría deberse al uso de Windows
Lyka
11

Resolví esto agregando

mongoose.models = {}

antes de la línea:

mongoose.model(<MODEL_NAME>, <MODEL_SCHEMA>)

Espero que resuelva tu problema

Toufiq
fuente
Esto fue lo que hice y lo solucionó. mongoose.connection.models = {};
Fortune
6

Para resolver esta comprobación si el modelo existe antes de realizar la creación:

if (!mongoose.models[entityDBName]) {
  return mongoose.model(entityDBName, entitySchema);
}
else {
  return mongoose.models[entityDBName];
}
Alpha BA
fuente
4

Sé que hay una solución aceptada, pero creo que la solución actual da como resultado una gran cantidad de texto estándar solo para que pueda probar los modelos. Mi solución es esencialmente tomar su modelo y colocarlo dentro de una función, lo que resulta en devolver el nuevo modelo si el modelo no se ha registrado, pero devolver el modelo existente si lo ha hecho.

function getDemo () {
  // Create your Schema
  const DemoSchema = new mongoose.Schema({
    name: String,
    email: String
  }, {
    collection: 'demo'
  })
  // Check to see if the model has been registered with mongoose
  // if it exists return that model
  if (mongoose.models && mongoose.models.Demo) return mongoose.models.Demo
  // if no current model exists register and return new model
  return mongoose.model('Demo', DemoSchema)
}

export const Demo = getDemo()

Abrir y cerrar conexiones por todas partes es frustrante y no se comprime bien.

De esta manera, si requiriera el modelo en dos lugares diferentes o más específicamente en mis pruebas, no obtendría errores y se devuelve toda la información correcta.

Moosecouture
fuente
2

Este problema puede ocurrir si define 2 esquemas diferentes con el mismo nombre de colección

Rohit Reddy Abbadi
fuente
1
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" } });
Rohit Jangid
fuente
1

Tuve el mismo problema, la razón fue que definí el esquema de un modelo en una función JS, deberían definirse globalmente en un módulo de nodo, no en una función.

beemaster
fuente
1

Hay otra forma de lanzar este error.

Tenga en cuenta que la ruta al modelo distingue entre mayúsculas y minúsculas.

En este ejemplo similar que involucra el modelo "Categoría", el error se produjo en estas condiciones:

1) La declaración require se mencionó en dos archivos: ..category.js y ..index.js 2) En el primero, el caso era correcto, en el segundo archivo no era el siguiente:

category.js

ingrese la descripción de la imagen aquí

index.js

ingrese la descripción de la imagen aquí

Tim
fuente
0

La definición de esquema debe ser única para una colección, no debe ser más de un esquema para una colección.

KARTHIKEYAN.A
fuente
0

es porque su esquema ya está, valide antes de crear un nuevo esquema.

var mongoose = require('mongoose');
module.exports = function () {
var db = require("../libs/db-connection")();
//schema de mongoose
var Schema = require("mongoose").Schema;

var Task = Schema({
    field1: String,
    field2: String,
    field3: Number,
    field4: Boolean,
    field5: Date
})

if(mongoose.models && mongoose.models.tasks) return mongoose.models.tasks;

return mongoose.model('tasks', Task);
Diego Santa Cruz Mendezú
fuente
0

Puede resolver esto fácilmente haciendo

delete mongoose.connection.models['users'];
const usersSchema = mongoose.Schema({...});
export default mongoose.model('users', usersSchema);
Shyam
fuente
0

Tengo una situación en la que tengo que crear el modelo dinámicamente con cada solicitud y debido a eso recibí este error, sin embargo, lo que usé para solucionarlo es usar el método deleteModel como el siguiente:

var contentType = 'Product'

var contentSchema = new mongoose.Schema(schema, virtuals);

var model = mongoose.model(contentType, contentSchema);

mongoose.deleteModel(contentType);

Espero que esto pueda ayudar a cualquiera.

Ingr.MTH
fuente
0
The reason of this issue is: 

you given the model name "users" in the line 
<<<var user = mongoose.model('users' {>>> in check.js file

and again the same model name you are giving in the insert file
<<< var user = mongoose.model('users',{ >>> in insert.js

This "users" name shouldn't be same when you declare a model that should be different 
in a same project.
Rohit Jangid
fuente
0

Para todas las personas que terminan aquí debido a una base de código con una mezcla de Typegoose y Mongoose :

Cree una conexión de base de datos para cada uno:

Mangosta:

module.exports = db_mongoose.model("Car", CarSchema);

Tipo ganso:

db_typegoose.model("Car", CarModel.schema, "cars");
Más allá del mar
fuente
0

Solo tengo un error al copiar y pegar. En una línea tenía el mismo nombre que en otro modelo (modelo de anuncio):

const Admin = mongoose.model('Ad', adminSchema);

Correcto es:

const Admin = mongoose.model('Admin', adminSchema);

Por cierto, si alguien tiene "guardado automático" y usa el índice para consultas como:

**adSchema**.index({title:"text", description:"text", phone:"text", reference:"text"})

Tiene que eliminar el índice y reescribir para el modelo correcto:

**adminSchema**.index({title:"text", description:"text", phone:"text", reference:"text"})
titoih
fuente
0

Resolví este problema haciendo esto

// Created Schema - Users
// models/Users.js
const mongoose = require("mongoose");

const Schema = mongoose.Schema;

export const userSchema = new Schema({
  // ...
});

Luego en otros archivos

// Another file
// index.js
import { userSchema } from "../models/Users";
const conn = mongoose.createConnection(process.env.CONNECTION_STRING, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
});
conn.models = {};
const Users = conn.model("Users", userSchema);
const results = await Users.find({});

Mejor solucion

let User;
try {
  User = mongoose.model("User");
} catch {
  User = mongoose.model("User", userSchema);
}

Espero que esto ayude...


fuente
No tengo ni idea de por qué es tan difícil dar explicaciones. Imagínese el tiempo que pierde mientras todos leen su código.
robertfoenix
-1

Dado que este problema ocurrió porque llamar al modelo en otro momento. Solucione este problema ajustando el código de su modelo en el bloque try catch. el código mecanografiado es así:

         Import {Schema, model} from 'mongoose';
         export function user(){
              try{
                   return model('user', new Schema ({
                            FirstName: String,
                            Last name: String
                     }));
              }
             catch{
                   return model('user');
              }
         }

Del mismo modo, también puede escribir código en js.

AKP
fuente
-2

Estás usando mongoose.model con el mismo nombre de variable "usuario" en check.js e insert.js.

David Khan
fuente
-4

Si está trabajando con expressjs, es posible que deba mover la definición de su modelo fuera de app.get (), por lo que solo se llama una vez cuando se crea una instancia del script.

Elesin Olalekan Fuad
fuente
esto no tiene sentido, los modelos de mangosta solo se definen una vez a menos que haya un problema con el nombre (por ejemplo, caso), una vez que se llama por primera vez, se inicializa, los requisitos futuros deben obtener la instancia y no reinstalarla
jonnie
Esta no es una solución.
Prathamesh More