Неможливо перезаписати модель, щойно скомпільована Mongoose


109

Не впевнений, що я роблю неправильно, ось мій 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 })
    });

і ось мій 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); 
   });

Щоразу, коли я намагаюся запустити check.js, я отримую цю помилку

Неможливо перезаписати модель "користувачів" після компіляції .

Я розумію, що ця помилка виникає через невідповідність схеми, але я не можу побачити, де це відбувається? Я досить новачок у мангусти та nodeJS.

Ось що я отримую з клієнтського інтерфейсу мого 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 
  } 
>

Ось що я отримую з клієнтського інтерфейсу моєї MongoDB: Версія оболонки MongoDB: 2.4.6 підключення до: test> використання event-db переключено на db event-db> db.users.find () {"_id": ObjectId ("52457d8718f83293205aaa95"), "name": "MyName", "email": "myemail@me.com", "password": "myPassword", "phone": 900001123, "_enable": true}>
Anathema .Запущено

Відповіді:


110

Помилка виникає через те, що у вас вже визначена схема, а потім ви знову визначаєте схему. Як правило, те, що ви повинні зробити, це інстанціювати схему один раз, а потім отримати глобальний об'єкт викликати його, коли він потребує.

Наприклад:

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
Уникайте експорту / вимагання моделей - якщо такі є refв інших моделях, це може призвести до кошмару залежності. Використовуйте var User = mongoose.model('user')замість require.
впр

1
Фактично може бути корисно змінити схему після визначення коду міграції схеми тестування.
Ігор Соарес

1
@wprl чи можете ви поясніть це далі? навіщо вимагати цього створювати проблеми?
varuog

Ця відповідь вводить в оману. Справа в тому, що якщо існує лише один екземпляр сервера mongoDB і більше Баз даних, якщо ви визначаєте в іншому додатку вже прийняту базу даних, ви отримали таку помилку. Просто так
Carmine Tambascia

174

Отже, ще одна причина, чому ви можете отримати цю помилку, це якщо ви використовуєте одну і ту ж модель у різних файлах, але ваш requireшлях має інший випадок. Наприклад, у моїй ситуації у мене було:

require('./models/User')в одному файлі, а потім в іншому файлі, де мені потрібен був доступ до наявної у мене моделі користувача require('./models/user').

Я думаю, що пошук модулів & мангуста трактує це як інший файл. Одного разу я переконався, що справа збігається в обох, це вже не було проблемою.


7
Це дійсно дуже складна проблема - я думаю, що це специфічно для ОС (це має відбуватися лише на Mac та Windows, оскільки FS ігнорує випадок). У мене була ця проблема, але, на щастя, я побачив вашу відповідь :) Дякую, Джоні!
Мирослав Недялков

6
ця проблема трапляється в моїй системі OS X.
lutaoact

Я ніколи про це не міг подумати, принаймні не інтуїтивно! дякую
Naveen Attri

Це було повністю моїм питанням. Я ніколи, хоча встановлення верхньої лапки з іменем ніколи не спричинить жодних проблем.
Сандіп Субєді

Це було те саме для мене. Усі файлові системи OS X та її файлова система (інсеситивні за замовчуванням)
mithril_knight

50

У мене виникла ця проблема під час тестування одиниць.

Перший раз, коли ви викликаєте функцію створення моделі, мангуст зберігає модель під наданим вами ключем (наприклад, "користувачі"). Якщо ви викликаєте функцію створення моделі одним і тим же клавішем не один раз, мангуст не дозволить вам перезаписати існуючу модель.

Ви можете перевірити, чи модель вже існує у мангуста за допомогою:

let users = mongoose.model('users')

Це призведе до помилки, якщо моделі не існує, тож ви можете обернути її в спробу / ловити, щоб отримати модель або створити її:

let users
try {
  users = mongoose.model('users')
} catch (error) {
  users = mongoose.model('users', <UsersSchema...>)
}

1
+1 У мене виникла та сама проблема, коли мені потрібно було встановити певну конфігурацію плагіна, перш ніж я міг визначити свою схему. Це взагалі не грало добре з моккою, і врешті-решт я здався і просто пішов із цим підходом до випробування
Віктор Пармар

Я використовую те саме, але навпаки, це зле:try exports.getModel = ()-> mongoose.model('User', userSchema) catch err exports.getModel = ()-> mongoose.model('User')
Andi Giga

Дякую, добрий пане, витративши 5+ годин на цю проблему. Я працював з безсерверним сервером на відміну від сервера вузлів, до якого я звик.
mxdi9i7

43

У мене виникло це питання під час "перегляду" тестів. Коли тести були відредаговані, годинник повторно запустив тести, але вони не вдалися через цю саме причину.

Я виправив це, перевіривши, чи існує модель, тоді використовую її, а інше створюю.

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

export const User = mongoose.models.User || mongoose.model('User', user);

Це працювало для мене. Я змінив module.export = Userдо export defaults User. Мені довелося також refsкористувачеві з інших моделей. Я НЕ впевнений , чому перехід від module.exportsдо export defaultприніс це питання. Тим не менш, ця відповідь, схоже, виправила її.
runios

3
до поганого mongoose.modelsне існує, принаймні в останніх версіях
Педро Луз

1
У мене була така ж проблема, але виправили її, очистивши всі моделі перед усіма тестами:for (let model in mongoose.models) delete mongoose.models[model]
Е. Сундін,

Мій тестовий скрипт виглядає так: "test": "NODE_ENV=test mocha --file mocha.config.js --watch"і в цьому файлі js config я маю before()і after()обробляти налаштування та відмову. @ E.Sundin запропонував ідеальне рішення тут, і це працює як шарм. Дякую!
Брендон Аасков

21

У мене виникла ця проблема, і це було не через визначення схеми, а швидше в режимі офлайн без сервера - я просто зумів вирішити це за допомогою цього:

serverless offline --skipCacheInvalidation

Про що йдеться тут https://github.com/dherault/serverless-offline/isissue/258

Будемо сподіватися, що це допомагає комусь, хто будує свій проект у режимі без сервера та працює в автономному режимі.


2
Дуже корисний. Дякую.
Тхань Труонг

2
Мені було прикро пропустити недійсність кешу, постійні перезавантаження, замість цього працюєmodule.exports = mongoose.models.Users || mongoose.model('Users', UsersSchema);
ask_io

ти зробив мій день
fstasi

Завдяки мільйонів!
AndyFaizan

Це було дуже корисно. Дякую!
ifiok

20

Якщо ви використовуєте без сервера офлайн і не хочете користуватися --skipCacheInvalidation, ви можете дуже добре використовувати:

module.exports = mongoose.models.Users || mongoose.model('Users', UsersSchema);

Ви також повинні використовувати це , якщо ви імпортуєте одну модель в іншу, навіть--skipCacheInvalidation
Powderham

1
Це точна відповідь, яку я шукав, для використання в Next.js. Я б хотів, щоб це було вище на сторінці!
Брендан Ніе

18

Якщо ви це зробили тут, можливо, у вас була та сама проблема, що і у мене. Моє питання полягало в тому, що я визначав іншу модель з такою ж назвою . Я назвав свою галерею та модель файлу "Файл". Чорт ти копіюєш і вставляєш!


11

Це сталося зі мною, коли я пишу так:

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

Однак справжній шлях - це "../myUser/User.js"


Змішування випадку контурів шляхів схеми при імпорті, здається, викликає цю проблему - перевірте, чи всі файли, що імпортують схему, використовують один і той же регістр.
Ендрю Купер

це нас врятувало! ми маємо відчуття, що це може бути пов’язано з використанням Windows
Lyka

11

Я вирішив це, додавши

mongoose.models = {}

перед рядком:

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

Сподіваюся, це вирішить вашу проблему


Це я і зробив, і це виправило. mongoose.connection.models = {};
Фортуна

6

Щоб вирішити цю перевірку, чи існує модель раніше для створення:

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

4

Я знаю, що є прийняте рішення, але я вважаю, що поточне рішення призводить до великої кількості котлів, щоб ви могли протестувати Моделі. Моє рішення полягає в тому, щоб взяти вас за модель і розмістити її всередині функції, що призведе до повернення нової моделі, якщо модель не була зареєстрована, але повернення існуючої моделі, якщо вона є.

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

Відкриття та закриття з'єднань у всьому місці неприємно і не стискається добре.

Таким чином, якби я вимагав від моделі двох різних місць або конкретніше в своїх тестах, я не отримав би помилок, і вся правильна інформація повертається.



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

У мене була така ж проблема, тому, що я визначив схему модель у функції JS, їх слід визначити глобально в модулі вузла, а не у функції.


1

Є ще один спосіб викинути цю помилку.

Майте на увазі, що шлях до моделі залежить від регістру.

У цьому подібному прикладі, що стосується моделі "Категорія", помилка була видана за таких умов:

1) Оператор вимагання був згаданий у двох файлах: ..category.js та ..index.js 2) Я перший, справа була правильною, у другому файлі це було не так:

category.js

введіть тут опис зображення

index.js

введіть тут опис зображення


0

Визначення схеми повинно бути унікальним для колекції, воно не повинно бути більше однієї схеми для колекції.


0

це тому, що ваша схема вже є, перевірити перед створенням нової схеми.

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

Ви можете легко вирішити це, зробивши

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

0

У мене виникає ситуація, коли мені доводиться динамічно створювати модель з кожним запитом, і через це я отримав цю помилку, однак те, що я використовував для її виправлення, використовує метод deleteModel, наприклад наступний:

var contentType = 'Product'

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

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

mongoose.deleteModel(contentType);

Я сподіваюся, що це може допомогти будь-кому.


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

Для всіх людей, які закінчуються тут із-за кодової бази з сумішшю Typegoose та Mongoose :

Створіть db-з'єднання для кожного:

Мангуст:

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

Вибір:

db_typegoose.model("Car", CarModel.schema, "cars");

0

У мене просто помилка копіювання вставки. В одному рядку я мав таку ж назву, що і в іншій моделі (модель оголошення):

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

Правильно:

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

До речі, якщо хтось має "автоматичне збереження", і використовуйте індекс для запитів, таких як:

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

Він повинен видалити індекс і переписати для правильної моделі:

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

0

Я вирішив це питання, зробивши це

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

const Schema = mongoose.Schema;

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

Потім в інших файлах

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

Краще рішення

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

Я сподіваюся, що це допомагає ...


Немає поняття, чому так важко дати пояснення. Уявіть час, який ви витрачаєте, коли всі читають ваш код.
robertfoenix

-1

Оскільки ця проблема сталася через те, що дзвонили моделі в інший раз. Вирішіть цю проблему, загорнувши код моделі в блок спробу лову. код машинопису такий:

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

Так само ви можете писати код і в js.


-2

Ви використовуєте mongoose.model з тим самим іменем змінної "user" у check.js та insert.js.


-4

Якщо ви працюєте з expressjs, можливо, вам доведеться перенести визначення моделі за межі app.get (), тому воно викликається лише один раз, коли сценарій інстанціюється.


це не має сенсу, мангузні моделі визначаються лише один раз, якщо не виникає проблема з називанням (наприклад, випадок), як тільки вона буде вперше названа, вона ініціалізується, майбутні потреби повинні просто отримати екземпляр, а не відновити його
jonnie

Це не рішення.
Пратамеш Більше
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.