ไม่สามารถเขียนทับโมเดลเมื่อรวบรวมพังพอนแล้ว


113

ไม่แน่ใจว่าฉันทำอะไรผิดนี่คือ 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 เชื่อมต่อกับ: ทดสอบ> ใช้ event-db เปลี่ยนเป็น db event-db> db.users.find () {"_id": ObjectId ("52457d8718f83293205aaa95"), "name": "MyName", "email": "myemail@me.com", "password": "myPassword", "phone": 900001123, "_enable": true}>
Anathema .Imbued

คำตอบ:


114

ข้อผิดพลาดเกิดขึ้นเนื่องจากคุณได้กำหนดสคีมาแล้วจากนั้นคุณกำลังกำหนดสคีมาอีกครั้ง โดยทั่วไปสิ่งที่คุณควรทำคือสร้างอินสแตนซ์สคีมาครั้งเดียวจากนั้นให้โกลบอลอ็อบเจ็กต์เรียกใช้เมื่อต้องการ

ตัวอย่างเช่น:

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

1
การเปลี่ยนสคีมามีประโยชน์จริง ๆ หลังจากกำหนดสำหรับการทดสอบรหัสการย้ายสคีมา
Igor Soarez

1
@wprl ช่วยอธิบายเพิ่มเติมได้ไหม ทำไมต้องสร้างปัญหา?
varuog

คำตอบนี้ทำให้เข้าใจผิด ความจริงก็คือหากมีอินสแตนซ์เซิร์ฟเวอร์ mongoDB เพียงตัวเดียวและฐานข้อมูลเพิ่มเติมหากคุณกำหนดฐานข้อมูลในแอปอื่นแล้วคุณจะได้รับข้อผิดพลาดดังกล่าว เพียงเท่านี้
Carmine Tambascia

179

อีกเหตุผลหนึ่งที่คุณอาจได้รับข้อผิดพลาดนี้คือถ้าคุณใช้โมเดลเดียวกันในไฟล์ต่างกัน แต่requireเส้นทางของคุณมีกรณีที่แตกต่างกัน ตัวอย่างเช่นในสถานการณ์ของฉันฉันมี:

require('./models/User')require('./models/user')ในไฟล์เดียวและจากนั้นในแฟ้มอื่นที่ผมจำเป็นต้องมีการเข้าถึงผู้ใช้รูปแบบที่ฉันมี

ฉันเดาว่าการค้นหาโมดูลและพังพอนกำลังถือว่าเป็นไฟล์อื่น เมื่อตรวจสอบจนแน่ใจแล้วว่าทั้งสองกรณีตรงกันแล้วก็ไม่มีปัญหาอีกต่อไป


7
นั่นเป็นปัญหาที่ยุ่งยากมากจริงๆ - ฉันคิดว่ามันเป็นระบบปฏิบัติการเฉพาะ (ควรเกิดขึ้นเฉพาะบน Mac และ Windows เนื่องจาก FS ไม่สนใจกรณีนี้) ฉันมีปัญหานี้ แต่โชคดีที่ได้เห็นคำตอบของคุณ :) ขอบคุณมากจอนนี่!
Miroslav Nedyalkov

6
ปัญหานี้เกิดขึ้นในระบบ OS X ของฉัน
lutaoact

ฉันไม่เคยคิดมาก่อนอย่างน้อยก็ไม่ได้สังหรณ์ใจ! ขอบคุณ
Naveen Attri

นั่นคือปัญหาของฉันโดยสิ้นเชิง ฉันไม่เคยว่าการตั้งชื่อด้านบนจะทำให้เกิดปัญหาใด ๆ
Sandip Subedi

นี่ก็เหมือนกันสำหรับฉัน ระบบไฟล์ hail 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 ฉันประสบปัญหาเดียวกันกับที่ฉันต้องตั้งค่าการกำหนดค่าสำหรับปลั๊กอินก่อนที่ฉันจะสามารถกำหนดสคีมาของฉันได้ สิ่งนี้เล่นกับมอคค่าได้ไม่ดีเลยและในที่สุดฉันก็ยอมแพ้และใช้วิธีการจับลองนี้
Victor Parmar

ฉันใช้แบบเดียวกัน แต่ในทางกลับกันมันชั่วร้าย:try exports.getModel = ()-> mongoose.model('User', userSchema) catch err exports.getModel = ()-> mongoose.model('User')
Andi Giga

ขอบคุณที่ดีเสียเวลา 5+ ชั่วโมงกับปัญหานี้ ฉันทำงานกับเซิร์ฟเวอร์ไร้เซิร์ฟเวอร์ซึ่งแตกต่างจากเซิร์ฟเวอร์โหนดที่ฉันคุ้นเคย
mxdi9i7

44

ฉันมีปัญหานี้ขณะ "ดู" การทดสอบ เมื่อแก้ไขการทดสอบแล้วนาฬิกาจะทำการทดสอบอีกครั้ง แต่ล้มเหลวเนื่องจากสาเหตุนี้

ฉันแก้ไขโดยการตรวจสอบว่ามีโมเดลอยู่หรือไม่จากนั้นใช้หรือไม่สร้างมันขึ้นมา

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ใช้ User จากรุ่นอื่นด้วย ฉันไม่แน่ใจว่าเหตุใดจึงเปลี่ยนจากmodule.exportsเป็นexport defaultนำปัญหานี้ อย่างไรก็ตามคำตอบนี้ดูเหมือนจะได้รับการแก้ไขแล้ว
runios

3
ถึงไม่ดีmongoose.modelsไม่มีอยู่จริงอย่างน้อยในเวอร์ชันล่าสุด
Pedro Luz

1
ฉันมีปัญหาเดียวกัน แต่แก้ไขด้วยการล้างทุกรุ่นก่อนการทดสอบทั้งหมด:for (let model in mongoose.models) delete mongoose.models[model]
อีซุนดิน

สคริปต์ทดสอบของฉันมีลักษณะดังนี้: "test": "NODE_ENV=test mocha --file mocha.config.js --watch"และในไฟล์ config js นั้นฉันมีbefore()และafter()จัดการการตั้งค่าและการฉีกขาด @ อีซุนดินเป็นโซลูชั่นที่สมบูรณ์แบบที่นี่และมันก็ใช้งานได้เหมือนมีเสน่ห์ ขอบคุณ!
Brandon Aaskov

22

หากคุณใช้ Serverless ออฟไลน์และไม่ต้องการใช้--skipCacheInvalidationคุณสามารถใช้:

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

คุณต้องใช้สิ่งนี้ด้วยหากคุณกำลังนำเข้าโมเดลหนึ่งภายในอีกรุ่นหนึ่งถึงแม้จะมี--skipCacheInvalidation
Powderham

1
นี่คือคำตอบที่แท้จริงที่ฉันกำลังมองหาเพื่อใช้ใน Next.js ฉันหวังว่าสิ่งนี้จะสูงขึ้นในหน้านี้!
Brendan Nee

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

สิ่งนี้มีประโยชน์มาก ขอบคุณ!
ifiok

19

ถ้าคุณทำที่นี่เป็นไปได้ว่าคุณมีปัญหาเดียวกันกับฉัน ปัญหาของฉันคือการที่ฉันได้รับการกำหนดรูปแบบอื่นที่มีชื่อเดียวกัน ฉันเรียกแกลเลอรีและโมเดลไฟล์ของฉันว่า "ไฟล์" คุณคัดลอกและวาง!


11

สิ่งนี้เกิดขึ้นกับฉันเมื่อฉันเขียนแบบนี้:

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

อย่างไรก็ตามเส้นทางที่แท้จริงคือ "../myUser/User.js"


กรณีการผสมของเส้นทางสคีมาเมื่อนำเข้าดูเหมือนจะทำให้เกิดปัญหานี้ - ตรวจสอบว่าไฟล์ทั้งหมดที่นำเข้าสคีมาใช้กรณีเดียวกัน
Andrew Cupper

สิ่งนี้ช่วยเรา! เรามีความรู้สึกว่าอาจเป็นเพราะใช้ 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

สิ่งนี้อาจทำให้บางคนได้รับความนิยม แต่ฉันก็ได้รับข้อผิดพลาดเช่นกันและตระหนักว่าฉันสะกดผิดโมเดลผู้ใช้ในการนำเข้า

ผิด: const User = require('./UserModel'); ถูกต้อง:const User = require('./userModel');

ไม่น่าเชื่อ แต่ลองพิจารณาดู


ดูเหมือนว่าจะมีข้อผิดพลาดในโหนด
Michael Hobbs

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) คำสั่ง need ถูกกล่าวถึงในสองไฟล์: ..category.js และ ..index.js 2) ฉันตัวแรกเคสถูกต้องในไฟล์ที่สองมันไม่เป็นดังนี้:

category.js

ป้อนคำอธิบายภาพที่นี่

index.js

ป้อนคำอธิบายภาพที่นี่


1

ฉันแก้ไขปัญหานี้โดยทำสิ่งนี้

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

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

สำหรับทุกคนที่จบลงที่นี่เพราะ codebase ที่มีการผสมผสานระหว่างTypegooseและMongooseกัน:

สร้างการเชื่อมต่อฐานข้อมูลสำหรับแต่ละรายการ:

พังพอน:

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

สิ่งที่คุณทำได้คือที่การส่งออกตรวจสอบให้แน่ใจว่าได้ส่งออกอินสแตนซ์ที่มีอยู่แล้วหากมีอยู่

โซลูชัน typescript:

import { Schema, Document, model, models } from 'mongoose';

const UserSchema: Schema = new Schema({
    name: {
        type: String
    }
});

export interface IUser extends Document {
    name: string
}

export default models.Users || model<IUser>('Users', UserSchema);

-1

เนื่องจากปัญหานี้เกิดขึ้นเนื่องจากการโทรหาโมเดลอีกครั้ง หลีกเลี่ยงปัญหานี้โดยการรวมรหัสรุ่นของคุณใน try catch block รหัส 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 () ดังนั้นจึงถูกเรียกเพียงครั้งเดียวเมื่อสคริปต์ถูกสร้างอินสแตนซ์


สิ่งนี้ไม่สมเหตุสมผลโมเดลพังพอนถูกกำหนดเพียงครั้งเดียวเว้นแต่จะมีปัญหากับการตั้งชื่อ (เช่นกรณี) เมื่อมีการเรียกใช้ครั้งแรกความต้องการในอนาคตควรได้รับอินสแตนซ์และไม่
คืนสถานะ

นี่ไม่ใช่วิธีแก้ปัญหา
พระธรรมเพิ่มเติม
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.