Impossible d'écraser le modèle une fois compilé Mongoose

109

Je ne sais pas ce que je fais mal, voici mon chèque.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 })
    });

et voici mon 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); 
   });

Chaque fois que j'essaye d'exécuter check.js, j'obtiens cette erreur

Impossible d'écraser le modèle «utilisateurs» une fois compilé .

Je comprends que cette erreur est due à une incompatibilité du schéma, mais je ne vois pas où cela se produit? Je suis assez nouveau pour mangouste et nodeJS.

Voici ce que j'obtiens de l'interface client de mon 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 
  } 
>
Anathème.
la source
Voici ce que j'obtiens de l'interface client de mon MongoDB: Version du shell MongoDB: 2.4.6 connexion à: test> use event-db commuté sur db event-db> db.users.find () {"_id": ObjectId ("52457d8718f83293205aaa95"), "name": "MyName", "email": "[email protected]", "password": "myPassword", "phone": 900001123, "_enable": true}>
Anathema .Imbued

Réponses:

110

L'erreur se produit car vous avez déjà défini un schéma, puis vous définissez à nouveau le schéma. En règle générale, vous devez instancier le schéma une fois, puis demander à un objet global de l'appeler quand il en a besoin.

Par exemple:

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
la source
69
Évitez d'exporter / d'exiger des modèles - le cas échéant ref, cela peut conduire à un cauchemar de dépendance. Utilisez à la var User = mongoose.model('user')place de require.
wprl
1
Il peut en fait être utile de modifier un schéma après avoir défini pour tester le code de migration de schéma.
Igor Soarez
1
@wprl pouvez-vous l'expliquer plus en détail? pourquoi l'exiger créerait-il un problème?
varuog
Cette réponse est trompeuse. Le fait est que s'il n'y a qu'une seule instance de serveur mongoDB et plusieurs bases de données, si vous définissez dans une autre application une base de données déjà prise, vous obtenez une telle erreur. Simplement comme ça
Carmine Tambascia
174

Donc, une autre raison pour laquelle vous pourriez obtenir cette erreur est si vous utilisez le même modèle dans différents fichiers mais que votre requirechemin a un cas différent. Par exemple dans ma situation j'avais:

require('./models/User')dans un fichier, puis dans un autre fichier où j'avais besoin d'accéder au modèle utilisateur que j'avais require('./models/user').

Je suppose que la recherche de modules et de mangouste le traite comme un fichier différent. Une fois que je me suis assuré que le cas correspondait aux deux, ce n'était plus un problème.

jonnie
la source
7
C'est en effet un problème très délicat - je pense que c'est spécifique au système d'exploitation (cela ne devrait se produire que sur Mac et Windows car le FS ignore le cas). J'ai eu ce problème, mais heureusement vu ta réponse :) Merci beaucoup Jonnie!
Miroslav Nedyalkov
6
ce problème se produit dans mon système OS X.
lutaoact
Je n'aurais jamais pu y penser, du moins pas intuitivement! merci
Naveen Attri
C'était totalement mon problème. Je n'ai jamais pensé que le fait de nommer des majuscules ne poserait jamais de problème.
Sandip Subedi
C'était la même chose pour moi. Tous saluent OS X et son système de fichiers (insensible à la casse par défaut)
mithril_knight
50

J'ai eu ce problème lors des tests unitaires.

La première fois que vous appelez la fonction de création de modèle, mangouste stocke le modèle sous la clé que vous fournissez (par exemple, «utilisateurs»). Si vous appelez plusieurs fois la fonction de création de modèle avec la même clé, mangouste ne vous laissera pas écraser le modèle existant.

Vous pouvez vérifier si le modèle existe déjà en mangouste avec:

let users = mongoose.model('users')

Cela lancera une erreur si le modèle n'existe pas, vous pouvez donc l'envelopper dans un try / catch afin d'obtenir le modèle ou de le créer:

let users
try {
  users = mongoose.model('users')
} catch (error) {
  users = mongoose.model('users', <UsersSchema...>)
}
BJ Anderson
la source
1
+1 J'avais le même problème où je devais configurer une configuration pour un plugin avant de pouvoir définir mon schéma. Cela n'a pas du tout bien joué avec le moka et à la fin j'ai abandonné et je suis juste allé avec cette approche d'essai de capture
Victor Parmar
J'utilise la même chose mais l'inverse, c'est méchant:try exports.getModel = ()-> mongoose.model('User', userSchema) catch err exports.getModel = ()-> mongoose.model('User')
Andi Giga
Merci bon monsieur, gaspillé plus de 5 heures sur ce problème. Je travaillais avec un serveur sans serveur contrairement au serveur de nœuds auquel je suis habitué.
mxdi9i7
43

J'ai eu ce problème en «regardant» les tests. Lorsque les tests ont été modifiés, la montre a relancé les tests, mais ils ont échoué pour cette raison même.

Je l'ai corrigé en vérifiant si le modèle existe puis l'utiliser, sinon le créer.

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

export const User = mongoose.models.User || mongoose.model('User', user);
ZephDavies
la source
Cela a fonctionné pour moi. J'avais changé le module.export = Useren export defaults User. J'ai également eu refsà l'utilisateur d'autres modèles. Je ne sais pas pourquoi passer de module.exportsà a export defaultcausé ce problème. Néanmoins, cette réponse semble l'avoir résolu.
runios
3
à mauvais mongoose.modelsn'existe pas, du moins dans les versions récentes
Pedro Luz
1
J'ai eu le même problème mais je l'ai résolu en effaçant tous les modèles avant tous les tests:for (let model in mongoose.models) delete mongoose.models[model]
E. Sundin
Mon script de test ressemble à ceci: "test": "NODE_ENV=test mocha --file mocha.config.js --watch"et dans ce fichier config js, j'ai un before()et after()pour gérer l'installation et le démontage. @ E.Sundin a fourni la solution parfaite ici, et cela fonctionne comme un charme. Je vous remercie!
Brandon Aaskov
21

J'ai rencontré ce problème et ce n'était pas à cause des définitions de schéma mais plutôt du mode hors ligne sans serveur - j'ai juste réussi à le résoudre avec ceci:

serverless offline --skipCacheInvalidation

Qui est mentionné ici https://github.com/dherault/serverless-offline/issues/258

J'espère que cela aidera quelqu'un d'autre qui construit son projet en mode sans serveur et en mode hors connexion.

Munyah
la source
2
Très utile. Merci.
Thanh Truong
2
J'ai trouvé ennuyeux de sauter l'invalidation du cache, les recharges constantes, au lieu de cela, cela fonctionnemodule.exports = mongoose.models.Users || mongoose.model('Users', UsersSchema);
demandé_io
tu as fait ma journée
fstasi
Mille mercis!
AndyFaizan
Cela a été très utile. Je vous remercie!
ifiok
20

Si vous utilisez Serverless hors ligne et que vous ne souhaitez pas utiliser --skipCacheInvalidation, vous pouvez très bien utiliser:

module.exports = mongoose.models.Users || mongoose.model('Users', UsersSchema);
julien
la source
Vous devez également l'utiliser si vous importez un modèle dans un autre, même avec--skipCacheInvalidation
Powderham
1
C'est la réponse exacte que je cherchais, à utiliser dans Next.js. J'aurais aimé que ce soit plus haut sur la page!
Brendan Nee
18

Si vous avez réussi ici, il est possible que vous ayez eu le même problème que moi. Mon problème était que je définissais un autre modèle avec le même nom . J'ai appelé ma galerie et mon modèle de fichier "Fichier". Bon sang, copiez et collez!

James Harrington
la source
11

Cela m'est arrivé lorsque j'écris comme ceci:

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

Cependant, le vrai chemin est '../myUser/User.js'

ip192
la source
Le mélange du cas des chemins de schéma lors de l'importation semble être à l'origine de ce problème - vérifiez que tous les fichiers important le schéma utilisent le même cas.
Andrew Cupper
cela nous a sauvés! nous avons le sentiment que cela pourrait être dû à l'utilisation de Windows
Lyka
11

J'ai résolu cela en ajoutant

mongoose.models = {}

avant la ligne:

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

J'espère que cela résout votre problème

Toufiq
la source
C'est ce que j'ai fait et cela a résolu le problème. mongoose.connection.models = {};
Fortune
6

Pour résoudre ce problème, vérifiez si le modèle existe avant de procéder à la création:

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

Je sais qu'il existe une solution acceptée, mais je pense que la solution actuelle se traduit par beaucoup de passe-partout juste pour que vous puissiez tester des modèles. Ma solution consiste essentiellement à prendre votre modèle et à le placer à l'intérieur d'une fonction, ce qui entraîne le retour du nouveau modèle si le modèle n'a pas été enregistré, mais le retour du modèle existant s'il l'a fait.

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

Ouvrir et fermer des connexions partout est frustrant et ne se comprime pas bien.

De cette façon, si je devais exiger le modèle à deux endroits différents ou plus spécifiquement dans mes tests, je n'obtiendrais pas d'erreurs et toutes les informations correctes seraient renvoyées.

Moosecouture
la source
2

Ce problème peut se produire si vous définissez 2 schémas différents avec le même nom de collection

Rohit Reddy Abbadi
la source
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
la source
1

J'ai eu le même problème, parce que j'ai défini un schéma un modèle dans une fonction JS, ils devraient être définis globalement dans un module de nœud, pas dans une fonction.

beemaster
la source
1

Il existe une autre façon de lancer cette erreur.

Gardez à l'esprit que le chemin d'accès au modèle est sensible à la casse.

Dans cet exemple similaire impliquant le modèle "Category", l'erreur a été générée dans les conditions suivantes:

1) L'instruction require était mentionnée dans deux fichiers: ..category.js et ..index.js 2) Dans le premier cas, le cas était correct, dans le second fichier ce n'était pas comme suit:

category.js

entrez la description de l'image ici

index.js

entrez la description de l'image ici

Tim
la source
0

La définition de schéma doit être unique pour une collection, elle ne doit pas être plus d'un schéma pour une collection.

KARTHIKEYAN.A
la source
0

est parce que votre schéma est déjà, validez avant de créer un nouveau schéma.

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ú
la source
0

Vous pouvez facilement résoudre ce problème en faisant

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

J'ai une situation où je dois créer le modèle dynamiquement avec chaque demande et à cause de cela, j'ai reçu cette erreur, cependant, ce que j'ai utilisé pour le corriger est en utilisant la méthode deleteModel comme suit:

var contentType = 'Product'

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

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

mongoose.deleteModel(contentType);

J'espère que cela pourrait aider n'importe qui.

Ingénieur MTH
la source
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
la source
0

Pour toutes les personnes se terminant ici à cause d'une base de code avec un mélange de Typegoose et Mongoose :

Créez une connexion db pour chacun:

Mangouste:

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

Typegoose:

db_typegoose.model("Car", CarModel.schema, "cars");
Au-delà de la mer
la source
0

J'ai juste une erreur de copier-coller. Dans une ligne, j'avais le même nom que dans un autre modèle (modèle d'annonce):

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

La bonne est:

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

Au fait, si quelqu'un a "auto-save", et utilise l'index pour des requêtes comme:

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

Il doit supprimer l'index et réécrire pour le modèle correct:

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

J'ai résolu ce problème en faisant cela

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

const Schema = mongoose.Schema;

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

Puis dans d'autres fichiers

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

Meilleure solution

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

J'espère que ça aide...


la source
Aucune idée pourquoi il est si difficile de fournir des explications. Imaginez le temps que vous perdez pendant que tout le monde lit votre code.
robertfoenix
-1

Depuis ce problème s'est produit parce que vous avez appelé le modèle une autre fois. Contournez ce problème en encapsulant le code de votre modèle dans le bloc try catch. le code dactylographié est comme ça -

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

De même, vous pouvez également écrire du code en js.

AKP
la source
-2

Vous utilisez mongoose.model avec le même nom de variable "user" dans check.js et insert.js.

David Khan
la source
-4

Si vous travaillez avec expressjs, vous devrez peut-être déplacer votre définition de modèle en dehors de app.get () afin qu'elle ne soit appelée qu'une seule fois lorsque le script est instancié.

Elesin Olalekan Fuad
la source
cela n'a pas de sens, les modèles mangouste ne sont définis qu'une seule fois sauf s'il y a un problème avec la dénomination (par exemple, cas), une fois qu'il est appelé pour la première fois, il est initialisé, le futur requiert juste d'obtenir l'instance et ne pas la réinstituer
jonnie
Ce n'est pas une solution.
Prathamesh More le