Nie można nadpisać modelu po skompilowaniu Mongoose

109

Nie wiem, co robię źle, oto mój 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 })
    });

a oto mój 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); 
   });

Za każdym razem, gdy próbuję uruchomić check.js, pojawia się ten błąd

Po skompilowaniu nie można nadpisać modelu „użytkowników” .

Rozumiem, że ten błąd wynika z niedopasowania schematu, ale nie widzę, gdzie to się dzieje? Jestem całkiem nowy w Mongoose i nodeJS.

Oto, co otrzymuję z interfejsu klienta mojej 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.Imbued
źródło
Oto, co otrzymuję z interfejsu klienta mojej bazy danych MongoDB: Wersja powłoki MongoDB: 2.4.6 łączenie się z: test> use event-db przełączone na db event-db> db.users.find () {"_id": ObjectId ("52457d8718f83293205aaa95"), "name": "MyName", "email": "[email protected]", "password": "myPassword", "phone": 900001123, "_enable": true}>
Anathema .Imbued

Odpowiedzi:

110

Błąd występuje, ponieważ masz już zdefiniowany schemat, a następnie definiujesz go ponownie. Ogólnie rzecz biorąc, powinieneś raz utworzyć wystąpienie schematu, a następnie wywołać go, gdy będzie potrzebny obiekt globalny.

Na przykład:

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
źródło
69
Unikaj eksportowania / wymagania modeli - jeśli którykolwiek ma refs do innych modeli, może to prowadzić do koszmaru zależności. Użyj var User = mongoose.model('user')zamiast require.
wprl
1
W rzeczywistości może być przydatna zmiana schematu po zdefiniowaniu do testowania kodu migracji schematu.
Igor Soarez
1
@wprl czy możesz to dalej wyjaśnić? dlaczego wymaganie tego stwarzałoby problem?
varuog
Ta odpowiedź jest myląca. Faktem jest, że jeśli jest tylko jedna instancja serwera mongoDB i więcej baz danych, jeśli zdefiniujesz w innej aplikacji bazę danych już zajętą, to wystąpi taki błąd. Po prostu
Carmine Tambascia
174

Więc innym powodem, dla którego możesz otrzymać ten błąd, jest użycie tego samego modelu w różnych plikach, ale requireścieżka ma inny przypadek. Na przykład w mojej sytuacji miałem:

require('./models/User')w jednym pliku, a następnie w innym, gdzie potrzebowałem dostępu do modelu użytkownika, który miałem require('./models/user').

Wydaje mi się, że wyszukiwanie modułów i mongoose traktuje go jako inny plik. Kiedy upewniłem się, że przypadek pasuje w obu przypadkach, nie było to już problemem.

jonnie
źródło
7
To rzeczywiście bardzo trudny problem - myślę, że jest to specyficzne dla systemu operacyjnego (powinno się to zdarzyć tylko na komputerach Mac i Windows, ponieważ FS ignoruje przypadek). Miałem ten problem, ale na szczęście zobaczyłem twoją odpowiedź :) Wielkie dzięki Jonnie!
Miroslav Nedyalkov
6
ten problem występuje w moim systemie OS X.
lutaoact
Nigdy bym o tym nie pomyślał, przynajmniej nie intuicyjnie! dzięki
Naveen Attri
To był całkowicie mój problem. Nigdy nie myślałem, że posiadanie nazwy z dużymi literami nigdy nie sprawi żadnego problemu.
Sandip Subedi
To było to samo dla mnie. Cały system plików Hail OS X i jego (domyślnie nie uwzględniający wielkości liter) system plików
mithril_knight
50

Miałem ten problem podczas testów jednostkowych.

Przy pierwszym wywołaniu funkcji tworzenia modelu mongoose przechowuje model pod podanym kluczem (np. „Użytkownicy”). Jeśli wywołasz funkcję tworzenia modelu z tym samym kluczem więcej niż raz, mangusta nie pozwoli Ci nadpisać istniejącego modelu.

Możesz sprawdzić, czy model już istnieje w mangusta za pomocą:

let users = mongoose.model('users')

Spowoduje to wyświetlenie błędu, jeśli model nie istnieje, więc możesz zawinąć go w try / catch, aby uzyskać model lub go utworzyć:

let users
try {
  users = mongoose.model('users')
} catch (error) {
  users = mongoose.model('users', <UsersSchema...>)
}
BJ Anderson
źródło
1
+1 Miałem ten sam problem, w którym musiałem skonfigurować jakąś konfigurację dla wtyczki, zanim mogłem zdefiniować mój schemat. To wcale nie grało dobrze z mokką i ostatecznie poddałem się i po prostu poszedłem z podejściem próbowania złapania
Victor Parmar
Używam tego samego, ale na odwrót, to jest okropne:try exports.getModel = ()-> mongoose.model('User', userSchema) catch err exports.getModel = ()-> mongoose.model('User')
Andi Giga
Dziękuję dobry panie, zmarnowałem ponad 5 godzin na ten problem. Pracowałem z serwerem bezserwerowym w przeciwieństwie do serwera węzłowego, do którego jestem przyzwyczajony.
mxdi9i7
43

Miałem ten problem podczas „oglądania” testów. Po edycji testów zegarek ponownie je przeprowadził, ale z tego właśnie powodu zakończyły się niepowodzeniem.

Naprawiłem to, sprawdzając, czy model istnieje, a następnie użyj go, w przeciwnym razie utwórz.

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

export const User = mongoose.models.User || mongoose.model('User', user);
ZephDavies
źródło
To zadziałało dla mnie. Miałem zmienił module.export = Usersię export defaults User. Miałem też refsużytkownika z innych modeli. Nie jestem pewien, dlaczego zmiana z module.exportsna export defaultprzyniosła ten problem. Niemniej jednak wydaje się, że ta odpowiedź rozwiązała problem.
runios
3
to bad mongoose.modelsnie istnieje, przynajmniej w ostatnich wersjach
Pedro Luz
1
Miałem ten sam problem, ale naprawiłem go, usuwając wszystkie modele przed wszystkimi testami:for (let model in mongoose.models) delete mongoose.models[model]
E. Sundin
Mój skrypt testowy wygląda tak: "test": "NODE_ENV=test mocha --file mocha.config.js --watch"iw tym pliku config js mam before()i after()do obsługi konfiguracji i porzucenia. @ E.Sundin zapewnił tutaj idealne rozwiązanie i działa jak urok. Dziękuję Ci!
Brandon Aaskov
21

Doświadczałem tego problemu i nie było to spowodowane definicjami schematu, ale raczej bezserwerowym trybem offline - właśnie udało mi się go rozwiązać w ten sposób:

serverless offline --skipCacheInvalidation

O czym wspomniano tutaj https://github.com/dherault/serverless-offline/issues/258

Mam nadzieję, że pomoże to komuś, kto buduje swój projekt w trybie bezserwerowym i działa w trybie offline.

munyah
źródło
2
Bardzo pomocne. Dzięki.
Thanh Truong
2
Uważam, że irytujące jest pomijanie unieważniania pamięci podręcznej, ciągłe module.exports = mongoose.models.Users || mongoose.model('Users', UsersSchema);
ponowne ładowanie
zrobiłeś mój dzień
fstasi
Stukrotne dzięki!
AndyFaizan
To było bardzo pomocne. Dziękuję Ci!
ifiok
20

Jeśli używasz Serverless w trybie offline i nie chcesz używać --skipCacheInvalidation, możesz bardzo dobrze użyć:

module.exports = mongoose.models.Users || mongoose.model('Users', UsersSchema);
juliański
źródło
Musisz go również użyć, jeśli importujesz jeden model do drugiego, nawet z--skipCacheInvalidation
Powderham
1
To jest dokładna odpowiedź, której szukałem, do wykorzystania w Next.js. Chciałbym, żeby to było wyżej na stronie!
Brendan Nee
18

Jeśli zrobiłeś to tutaj, możliwe, że miałeś ten sam problem, co ja. Mój problem polegał na tym, że definiowałem inny model o tej samej nazwie . Nazwałem moją galerię i model pliku „Plik”. Cholera, kopiuj i wklejaj!

James Harrington
źródło
11

Przydarzyło mi się to, kiedy piszę tak:

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

Jednak prawdziwa ścieżka to „../myUser/User.js”

ip192
źródło
Wydaje się, że mieszanie wielkości liter ścieżek schematu podczas importu wydaje się powodować ten problem - sprawdź, czy wszystkie pliki importujące schemat używają tego samego przypadku.
Andrew Cupper
to nas uratowało! mamy wrażenie, że może to być spowodowane używaniem okien
Lyka
11

Rozwiązałem to, dodając

mongoose.models = {}

przed linią:

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

Mam nadzieję, że to rozwiązuje twój problem

Toufiq
źródło
To właśnie zrobiłem i to naprawiło. mongoose.connection.models = {};
Fortune
6

Aby rozwiązać ten problem, sprawdź, czy model istnieje przed utworzeniem:

if (!mongoose.models[entityDBName]) {
  return mongoose.model(entityDBName, entitySchema);
}
else {
  return mongoose.models[entityDBName];
}
Alpha BA
źródło
4

Wiem, że istnieje akceptowalne rozwiązanie, ale uważam, że obecne rozwiązanie prowadzi do wielu schematów, abyś mógł przetestować modele. Moje rozwiązanie polega w istocie na przeniesieniu modelu i umieszczeniu go wewnątrz funkcji powodującej zwrócenie nowego Modelu, jeśli Model nie został zarejestrowany, ale zwraca istniejący Model, jeśli tak.

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

Otwieranie i zamykanie połączeń w każdym miejscu jest frustrujące i nie uciska dobrze.

W ten sposób, gdybym wymagał od modelu dwóch różnych miejsc lub dokładniej w moich testach, nie dostałbym błędów i zwracane są wszystkie prawidłowe informacje.

Moosecouture
źródło
2

Ten problem może wystąpić, jeśli zdefiniujesz 2 różne schematy o tej samej nazwie kolekcji

Rohit Reddy Abbadi
źródło
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
źródło
1

Miałem ten sam problem, ponieważ zdefiniowałem schemat i model w funkcji JS, powinny być zdefiniowane globalnie w module węzła, a nie w funkcji.

pszczelarz
źródło
1

Istnieje inny sposób na zgłoszenie tego błędu.

Należy pamiętać, że w ścieżce do modelu rozróżniana jest wielkość liter.

W tym podobnym przykładzie dotyczącym modelu „Kategoria” błąd został zgłoszony w następujących warunkach:

1) Wymagane stwierdzenie pojawiło się w dwóch plikach: ..category.js i ..index.js 2) W pierwszym przypadku sprawa była poprawna, w drugim nie było tak:

category.js

wprowadź opis obrazu tutaj

index.js

wprowadź opis obrazu tutaj

Tim
źródło
0

Definicja schematu powinna być unikalna dla kolekcji, nie powinna zawierać więcej niż jednego schematu dla kolekcji.

KARTHIKEYAN.A
źródło
0

wynika z tego, że Twój schemat już istnieje, sprawdź poprawność przed utworzeniem nowego schematu.

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ú
źródło
0

Możesz łatwo rozwiązać ten problem, robiąc

delete mongoose.connection.models['users'];
const usersSchema = mongoose.Schema({...});
export default mongoose.model('users', usersSchema);
Shyam
źródło
0

Mam sytuację, w której muszę dynamicznie tworzyć model z każdym żądaniem i przez to otrzymałem ten błąd, jednak to, co naprawiłem, to metoda deleteModel jak poniżej:

var contentType = 'Product'

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

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

mongoose.deleteModel(contentType);

Mam nadzieję, że to mogłoby pomóc każdemu.

Engr.MTH
źródło
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
źródło
0

Dla wszystkich osób kończących się tutaj z powodu bazy kodów z mieszanką Typegoose i Mongoose :

Utwórz połączenie db dla każdego z nich:

Mangusta:

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

Typegoose:

db_typegoose.model("Car", CarModel.schema, "cars");
Za morzem
źródło
0

Po prostu mam błąd wklejania kopii. W jednej linii miałem taką samą nazwę jak w innym modelu (model reklamowy):

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

Prawidłowe to:

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

Nawiasem mówiąc, jeśli ktoś ma „automatyczne zapisywanie” i używa indeksu do zapytań takich jak:

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

Musi usunąć indeks i przepisać na poprawny model:

**adminSchema**.index({title:"text", description:"text", phone:"text", reference:"text"})
titoih
źródło
0

Rozwiązałem ten problem, robiąc to

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

const Schema = mongoose.Schema;

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

Następnie w innych plikach

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

Lepsze rozwiązanie

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

Mam nadzieję, że to pomoże...


źródło
Nie mam pojęcia, dlaczego tak trudno jest udzielić wyjaśnień. Wyobraź sobie, ile czasu tracisz, gdy wszyscy czytają Twój kod.
robertfoenix
-1

Ponieważ ten problem wystąpił z powodu innego wywołania modelu. Obejdź ten problem, opakowując kod modelu w bloku try catch. kod maszynowy wygląda następująco -

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

Podobnie możesz pisać kod w js.

AKP
źródło
-2

Używasz mongoose.model z tą samą nazwą zmiennej „user” w check.js i insert.js.

David Khan
źródło
-4

Jeśli pracujesz z expressjs, może być konieczne przeniesienie definicji modelu poza app.get (), aby była wywoływana tylko raz, gdy skrypt jest tworzony.

Elesin Olalekan Fuad
źródło
to nie ma sensu, modele mangusty są definiowane tylko raz, chyba że występuje problem z nazewnictwem (np. przypadek), po pierwszym wywołaniu jest inicjalizowany, przyszłe wymagania powinny po prostu pobrać instancję i nie odtwarzać jej
jonnie
To nie jest rozwiązanie.
Prathamesh More