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 switched to db event-db> db.users.find () { "_id": ObjectId ( "52457d8718f83293205aaa95"), "name": "MyName", "email": "myemail@me.com", "password": "myPassword", "phone": 900001123, "_enable": true}>
Anathema .Imbued

답변:


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다른 모델에 s가있는 경우 종속성 악몽으로 이어질 수 있습니다. 사용 var User = mongoose.model('user')대신에 require.
wprl

1
스키마 마이그레이션 코드를 테스트하기 위해 정의한 후 스키마를 변경하는 것이 실제로 유용 할 수 있습니다.
Igor Soarez

1
@wprl 더 설명해 주시겠습니까? 왜 그것을 요구하면 문제가 발생합니까?
varuog

이 대답은 잘못된 것입니다. 사실 mongoDB 서버 인스턴스가 하나만 있고 데이터베이스가 더 많은 경우 다른 앱에서 이미 가져온 데이터베이스를 정의하면 이러한 오류가 발생합니다. 간단하게
Carmine Tambascia

174

따라서이 오류가 발생할 수있는 또 다른 이유는 다른 파일에서 동일한 모델을 사용하지만 require경로가 다른 경우입니다. 예를 들어 내 상황에서 나는 다음을 가졌다.

require('./models/User')한 파일에서 내가 가지고있는 사용자 모델에 액세스해야하는 다른 파일에서 require('./models/user').

나는 모듈과 몽구스를 찾는 것이 그것을 다른 파일로 취급하고 있다고 생각합니다. 케이스가 둘 다 일치하는지 확인한 후에는 더 이상 문제가되지 않았습니다.


7
그것은 실제로 매우 까다로운 문제입니다. OS에 따라 다릅니다 (FS가 케이스를 무시하므로 Mac과 Windows에서만 발생해야합니다). 나는이 문제가 있었지만 운 좋게 당신의 대답을 보았습니다 :) Jonnie 많이 감사합니다!
Miroslav Nedyalkov 2015

6
이 문제는 내 OS X 시스템에서 발생합니다.
lutaoact

적어도 직감적으로는 생각지도 못했어요! 감사합니다
Naveen Attri 2016 년

그것이 제 문제였습니다. 대문자로 명명하면 문제가 발생하지 않습니다.
Sandip Subedi 2016

저도 마찬가지였습니다. 모든 hail OS X 및 해당 (기본적으로 대소 문자 구분) 파일 시스템
mithril_knight 2016

50

단위 테스트 중에이 문제가 발생했습니다.

모델 생성 기능을 처음 호출 할 때 mongoose는 사용자가 제공 한 키 (예 : '사용자') 아래에 모델을 저장합니다. 동일한 키로 모델 생성 함수를 두 번 이상 호출하면 mongoose는 기존 모델을 덮어 쓰지 못하게합니다.

모델이 이미 몽구스에 있는지 확인할 수 있습니다.

let users = mongoose.model('users')

모델이 존재하지 않으면 오류가 발생하므로 모델을 가져 오거나 생성하기 위해 try / catch로 래핑 할 수 있습니다.

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

1
+1 스키마를 정의하기 전에 플러그인에 대한 일부 구성을 설정해야하는 동일한 문제가 발생했습니다. 이것은 전혀 모카 잘 재생되지 않았고 결국 나는 포기하고 그냥이 시도 캐치 접근 갔다
빅터 Parmar을

나는 똑같은 것을 사용하고 있지만 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 = Userexport defaults User. 나는 또한 refs다른 모델의 사용자를 사용해야했습니다. 에서이 문제 module.exportsexport default가져 오는 이유를 잘 모르겠습니다 . 그럼에도 불구 하고이 대답은 그것을 고친 것 같습니다.
runios

3
나쁜에 mongoose.models적어도 최신 버전에 존재하지 않습니다
페드로 루즈

1
나는 같은 문제가 있었지만 모든 테스트 전에 모든 모델을 지우고 수정했습니다.for (let model in mongoose.models) delete mongoose.models[model]
E. Sundin

내 테스트 스크립트 외모가 너무 좋아 : "test": "NODE_ENV=test mocha --file mocha.config.js --watch"그 설정의 js 파일에 내가 가지고 before()after()핸들 설치 및 해체에. @ E.Sundin은 여기에 완벽한 솔루션을 제공했으며 매력처럼 작동합니다. 감사합니다!
Brandon Aaskov 19

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

서버리스를 오프라인으로 사용 중이고을 사용하지 않으려면 --skipCacheInvalidation다음을 매우 잘 사용할 수 있습니다.

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

한 모델을 다른 모델로 가져 오는 경우에도 사용해야합니다.--skipCacheInvalidation
Powderham

1
이것은 Next.js에서 사용하기 위해 찾고 있던 정확한 대답입니다. 나는 이것이 페이지에서 더 높았 으면 좋겠다!
Brendan Nee

18

당신이 여기에서 그것을 만들었다면 당신은 내가 한 것과 같은 문제를 겪었을 가능성이 있습니다. 내 문제는 내가 같은 이름을 가진 다른 모델을 정의 하고 있었다는 것 입니다. 내 갤러리와 파일 모델을 "파일"이라고했습니다. 복사해서 붙여 넣으세요!


11

이렇게 쓸 때 이런 일이 일어났습니다.

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

그러나 실제 경로는 '../myUser/User.js'입니다.


가져올 때 스키마 경로의 대소 문자를 혼합하면이 문제가 발생하는 것 같습니다. 스키마를 가져 오는 모든 파일이 동일한 대소 문자를 사용하는지 확인하십시오.
앤드류 구리

이것은 우리를 구했습니다! 우리는 이것이 창문을 사용했기 때문일지도 모른다고 느낍니다
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()

모든 곳에서 연결을 열고 닫는 것은 실망스럽고 잘 압축되지 않습니다.

이런 식으로 두 개의 다른 장소 또는 더 구체적으로 테스트에서 모델을 요구하는 경우 오류가 발생하지 않고 모든 올바른 정보가 반환됩니다.



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

이 오류를 발생시키는 또 다른 방법이 있습니다.

모델 경로는 대소 문자를 구분합니다.

"Category"모델과 관련된이 유사한 예에서는 다음 조건에서 오류가 발생했습니다.

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

나는 이것이 누구에게나 도움이되기를 바랍니다.


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

TypegooseMongoose 가 혼합 된 코드베이스로 인해 여기서 끝나는 모든 사람들을 위해 :

각각에 대해 db 연결을 만듭니다.

몽구스 :

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

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

이 문제는 나중에 모델을 호출했기 때문에 발생했습니다. 모델 코드를 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

check.js 및 insert.js에서 동일한 변수 이름 "user"로 mongoose.model을 사용하고 있습니다.


-4

expressjs로 작업하는 경우 모델 정의를 app.get () 외부로 이동해야 할 수 있으므로 스크립트가 인스턴스화 될 때 한 번만 호출됩니다.


이것은 의미가 없습니다. mongoose 모델은 이름 지정 (예 : 케이스)에 문제가없는 한 한 번만 정의됩니다. 일단 처음 호출되면 초기화되고, 나중에 인스턴스를 가져
오고

이것은 해결책이 아닙니다.
Prathamesh More
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.