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接続先:テスト>イベントイベントデータベースをデータベースイベントデータベースに切り替え> 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 2013

1
スキーマ移行コードをテストするために定義した後でスキーマを変更すると、実際に役立ちます。
イゴールソアレス2014年

1
@wprlさらに説明していただけますか?なぜそれを要求すると問題が発生するのですか?
varuog 2018年

この答えは誤解を招くものです。実際、mongoDBサーバーインスタンスが1つとデータベースが複数ある場合、別のアプリでデータベースを既に定義していると、そのようなエラーが発生します。単にその通り
カーマインタンバスシア

174

したがって、このエラーが発生するもう1つの理由は、異なるファイルで同じモデルを使用しているが、requireパスの大文字と小文字が異なる場合です。たとえば、私の状況では次のことがありました。

require('./models/User')あるファイルと、別のファイルで、私が持っていたUserモデルにアクセスする必要がありましたrequire('./models/user')

モジュールとmongooseのルックアップは別のファイルとして扱っていると思います。ケースが両方で一致することを確認したら、それは問題ではなくなりました。


7
これは確かに非常にトリッキーな問題です-私はそれがOS固有であると思います(FSがケースを無視するため、MacとWindowsでのみ発生するはずです)。私はこの問題を抱えていましたが、幸いにもあなたの答えを見ました:)ジョニー、どうもありがとう!
Miroslav Nedyalkov

6
この問題は私のOS Xシステムで発生します。
lutaoact 2016

少なくとも直感的には、私はそれについて考えたことはなかったでしょう!ありがとう
Naveen Attri

それが完全に私の問題でした。大文字の名前を付けると問題が発生することはありません。
Sandip Subedi

これは私にとっても同じでした。すべての雹OS Xとその(デフォルトでは大文字と小文字は区別されない)ファイルシステム
mithril_knight 2016年

50

ユニットテスト中にこの問題が発生しました。

モデル作成関数を初めて呼び出すとき、mongooseは指定されたキー(「ユーザー」など)の下にモデルを保存します。同じキーを使用してモデル作成関数を複数回呼び出す場合、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スキーマを定義する前にプラグインの構成をセットアップする必要があるのと同じ問題がありました。これはモカとまったくうまくいかなかったので、結局私はあきらめてこのトライキャッチアプローチを採用しました
Victor Parmar

:私はの邪悪なことを、同じですが、他の方法で回避を使用しています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);

これでうまくいきました。をに変更しmodule.export = Userましたexport defaults Userrefs他のモデルのユーザーも使用する必要がありました。からmodule.exportsに変更するとexport default、この問題が発生した理由がわかりません。それにもかかわらず、この答えはそれを修正したようです。
runios 2018

3
mongoose.models少なくとも最近のバージョンでは、悪いものは存在しません
ペドロ・ルス

1
私は同じ問題があったが、すべてのテストの前にすべてのモデルをクリアするとそれを固定:for (let model in mongoose.models) delete mongoose.models[model]
E.サンディン

私のテストスクリプトは次のようになります。"test": "NODE_ENV=test mocha --file mocha.config.js --watch"その構成のjsファイルには、セットアップと破棄を処理するbefore()after()があります。@ E.Sundinはここで完璧なソリューションを提供し、それは魅力のように機能します。ありがとうございました!
Brandon Aaskov

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);
読み込み

あなたは私の日を作った
fstasi

どうもありがとう!
AndyFaizan 2018年

これはとても役に立ちました。ありがとうございました!
ifiok 2018年

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」です。


インポート時にスキーマパスの大文字と小文字を混在させると、この問題が発生するようです-スキーマをインポートするすべてのファイルで同じ大文字と小文字が使用されていることを確認してください。
Andrew Cupper 2017

これは私たちを救った!これは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()

至る所で接続を開いたり閉じたりするとイライラさせられ、うまく圧縮されません。

このように、モデルで2つの異なる場所、より具体的にはテストで必要な場合、エラーは発生せず、すべての正しい情報が返されます。


2

この問題は、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

このエラーをスローする別の方法があります。

モデルへのパスでは大文字と小文字が区別されることに注意してください。

「Category」モデルを含むこの同様の例では、次の条件でエラーがスローされました。

1)requireステートメントが..category.jsと..index.jsの2つのファイルで言及されていた2)最初のケースは正しく、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);

タイプグース:

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

0

コピーの貼り付けを間違えただけです。1行で、他のモデル(広告モデル)と同じ名前にしました。

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ブロックでラップすることにより、この問題を回避します。typescriptコードはこのようなものです-

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

同様に、jsでもコードを記述できます。



-4

expressjsを使用している場合は、モデル定義をapp.get()の外に移動して、スクリプトがインスタンス化されたときに一度だけ呼び出されるようにする必要がある場合があります。


これは意味がありません。マングースモデルは、名前付け(例:case)に問題がない限り、一度だけ定義されます。最初に呼び出された後、初期化されます
。future

これは解決策ではありません。
Prathamesh More
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.