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" : "myemail@me.com", 
    "password" : "myPassword", 
    "phone" : 900001123, 
    "_enable" : true 
  } 
>

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": "myemail@me.com", "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); 
});

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.


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...>)
}

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

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.


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

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!


11

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

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

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


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


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];
}

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.



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

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.


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


0

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


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

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

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.


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.

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

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

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...


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.


-2

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


-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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.