Не удается перезаписать модель после компиляции 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, я получаю эту ошибку

После компиляции нельзя перезаписать «пользовательскую» модель .

Я понимаю, что эта ошибка возникает из-за несоответствия схемы, но я не вижу, где это происходит? Я новичок в mongoose и 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> use event-db переключена на db event-db> db.users.find () {"_id": ObjectId ("52457d8718f83293205aaa95"), "name": "MyName", "email": "myemail@me.com", "password": "myPassword", "phone": 900001123, "_enable": true}>
Анафема Создан

Ответы:

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); 
});
thtsigma
источник
69
Избегайте экспорта / требования моделей - если какие-либо из них имеют отношение refк другим моделям, это может привести к кошмару зависимостей. Используйте var User = mongoose.model('user')вместо require.
wprl,
1
На самом деле может быть полезно изменить схему после определения кода миграции схемы для тестирования.
Игорь Соарез
1
@wprl, не могли бы вы объяснить это дальше? почему это может создать проблему?
varuog
Этот ответ вводит в заблуждение. Дело в том, что если есть только один экземпляр сервера mongoDB и несколько баз данных, если вы определяете в другом приложении уже занятую базу данных, вы получаете такую ​​ошибку. Просто так
Carmine Tambascia
176

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

require('./models/User')в одном файле, а затем в другом, где мне нужен был доступ к модели User, которая у меня была require('./models/user').

Я предполагаю, что поиск модулей и mongoose рассматривает его как другой файл. Как только я убедился, что корпус соответствует обоим, это больше не было проблемой.

джонни
источник
7
Это действительно очень сложная проблема - я думаю, что это зависит от ОС (это должно происходить только на Mac и Windows, поскольку FS игнорирует этот случай). У меня была эта проблема, но, к счастью, я увидел твой ответ :) Большое спасибо, Джонни!
Мирослав Недялков
6
эта проблема возникает в моей системе OS X.
lutaoact
Я бы никогда об этом не подумал, по крайней мере, интуитивно! спасибо
Naveen Attri
В этом и заключалась моя проблема. Я никогда не думал, что имя в верхнем регистре вызовет какие-либо проблемы.
Sandip Subedi
То же было и со мной. Приветствую OS X и ее файловую систему (по умолчанию без учета регистра)
mithril_knight
50

У меня возникла эта проблема во время модульного тестирования.

При первом вызове функции создания модели mongoose сохраняет модель под указанным вами ключом (например, «пользователи»). Если вы вызовете функцию создания модели с одним и тем же ключом более одного раза, мангуст не позволит вам перезаписать существующую модель.

Вы можете проверить, существует ли уже модель в мангусте с помощью:

let users = mongoose.model('users')

Это вызовет ошибку, если модель не существует, поэтому вы можете обернуть ее в try / catch, чтобы либо получить модель, либо создать ее:

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')
Энди Гига
Спасибо, сэр, потратил более 5 часов на эту проблему. Я работал с бессерверным сервером, в отличие от узлового сервера, к которому я привык.
mxdi9i7
43

У меня возникла эта проблема во время просмотра тестов. Когда тесты были отредактированы, часы повторно запустили тесты, но они потерпели неудачу именно по этой причине.

Я исправил это, проверив, существует ли модель, затем используйте ее, иначе создайте ее.

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

export const User = mongoose.models.User || mongoose.model('User', user);
ZephDavies
источник
Это сработало для меня. Я изменил module.export = Userк export defaults User. Еще мне пришлось refsUser от других моделей. Я не понимаю, почему при переходе с 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-файле конфигурации у меня есть before()и after()для настройки и демонтажа. @ E.Sundin предоставил здесь идеальное решение, и оно прекрасно работает. Спасибо!
Brandon
21

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

serverless offline --skipCacheInvalidation

Это упомянуто здесь https://github.com/dherault/serverless-offline/issues/258

Надеюсь, это поможет кому-то еще, кто строит свой проект в бессерверном режиме и работает в автономном режиме.

Муня
источник
2
Очень полезно. Спасибо.
Thanh Truong
2
Меня раздражает пропуск недействительности кеша, постоянные перезагрузки, вместо этого это работаетmodule.exports = mongoose.models.Users || mongoose.model('Users', UsersSchema);
ask_io
ты сделал мой день
fstasi
Бесконечно благодарен!
AndyFaizan
Это было очень полезно. Спасибо!
ifiok
20

Если вы используете Serverless в автономном режиме и не хотите использовать --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".

ip192
источник
Похоже, что эта проблема возникает из-за смешения путей схемы при импорте - убедитесь, что все файлы, импортирующие схему, используют один и тот же регистр.
Эндрю Куппер,
это спасло нас! у нас есть ощущение, что это может быть из-за использования окон
Lyka
11

Я решил это, добавив

mongoose.models = {}

перед строкой:

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

Надеюсь, это решит вашу проблему

Туфик
источник
Это то, что я сделал, и это исправило. mongoose.connection.models = {};
Fortune
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()

Открытие и закрытие соединений повсюду раздражает и плохо сжимается.

Таким образом, если бы я потребовал модель в двух разных местах или, более конкретно, в моих тестах, я бы не получил ошибок, и была бы возвращена вся правильная информация.

Moosecouture
источник
2

Эта проблема может возникнуть, если вы определите две разные схемы с одинаковым именем коллекции.

Рохит Редди Аббади
источник
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) Оператор require упоминался в двух файлах: ..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);

Надеюсь, это кому-нибудь поможет.

Engr.MTH
источник
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. :

Создайте соединение с БД для каждого из них:

Мангуст:

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

Typegoose:

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"})
Titoih
источник
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);
}

Надеюсь, это поможет...


источник
Понятия не имею, почему так сложно давать объяснения. Представьте, сколько времени вы тратите, пока все читают ваш код.
Робертфеникс
-1

Поскольку эта проблема возникла из-за вызова модели в другой раз. Обойдите эту проблему, заключив код модели в блок try catch. машинописный код выглядит так -

         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 (), чтобы оно вызывалось только один раз при создании экземпляра скрипта.

Элесин Олалекан Фуад
источник
это не имеет смысла, модели мангуста определяются только один раз, если нет проблем с именованием (например, case), после первого вызова он инициализируется, в будущем требуется просто получить экземпляр, а не восстанавливать его
jonnie
Это не выход.
Prathamesh More