Anathema.Imbued
Anathema.Imbued

Reputation: 3491

Cannot overwrite model once compiled Mongoose

Not Sure what I'm doing wrong, here is my 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 })
    });

and here is my 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); 
   });

Whenever I'm trying to run check.js, I'm getting this error

Cannot overwrite 'users' model once compiled.

I understand that this error comes due to mismatching of Schema, but I cannot see where this is happening ? I'm pretty new to mongoose and nodeJS.

Here is what I'm getting from the client interface of my 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" : "[email protected]", 
    "password" : "myPassword", 
    "phone" : 900001123, 
    "_enable" : true 
  } 
>

Upvotes: 219

Views: 254830

Answers (30)

pa4080
pa4080

Reputation: 941

I've upgraded from Mongoose 8.5 to 8.8 and the latest Typescript 5.6.3. Before that the types was inferred nicely and my code was much simple:

interface AboutEntryDoc { _id: ObjectId; title: string; desc: string; }
interface NewAboutEntryDoc extends Omit<AboutEntryDoc, "_id"> {}

const AboutEntrySchema = new Schema({
  title: { type: String, required: [true, "Title is required!"], },
  desc: { type: String, required: [true, "Description is required!"] }
})

const AboutEntry = models.AboutEntry || model("AboutEntry", AboutEntrySchema);
export default AboutEntry;

Than now:

const AboutEntrySchema = new Schema<AboutEntryDoc>({
  title: { type: String, required: [true, "Title is required!"], },
  desc: { type: String, required: [true, "Description is required!"] }
})

type AboutEntryModel = Model<AboutEntryDoc>;

const AboutEntry =
  (models.AboutEntry as AboutEntryModel) || model<AboutEntryDoc>("AboutEntry", AboutEntrySchema);

export default AboutEntry;

Upvotes: 0

maxeth
maxeth

Reputation: 1515

I had a pretty unique setup & solution but it may still help someone:

I have a (pnpm) workspace with several packages, e.g.:

  • core
  • otherPackage1
  • otherPackage2

where the core package defines primitive models (e.g. for authentication) that are re-used in all sorts of packages.

Now, in one of the other packages, I defined a custom User model and was not intending to use the User model from the core package, but was trying to import a type defined in the user.model file of the core package. The obvious solution was defining that type in a separate file, to omit registering another user model with the same name.

This is somewhat related to the issue of importing the same file with different spelling.

Upvotes: 0

Nikhil Singh
Nikhil Singh

Reputation: 21

I have the same issue but when i check my code then I figure out that there is a typo in code

Error Code 👇

import mongoose from "mongoose";

const contentSchema = new mongoose.Schema({
    content: {
        type: String,
        required: true
    },
}, { timestamps: true })

const ContentPost = mongoose.Schema.contents || mongoose.model("contents", contentSchema);

export default ContentPost;

Error Free Code 👇

import mongoose from "mongoose";

const contentSchema = new mongoose.Schema({
    content: {
        type: String,
        required: true
    },
}, { timestamps: true })

const ContentPost = mongoose.models.contents || mongoose.model("contents", contentSchema);

export default ContentPost;

I write the Schema in place of of model const ContentPost = mongoose.Schema.contents || mongoose.model("contents", contentSchema);

Upvotes: 2

Rohit Patel
Rohit Patel

Reputation: 49

mongoose.model('Customer', customerSchema): This creates a Mongoose model named 'Customer' using the 'customerSchema' schema if the 'Customer' model doesn't exist

module.exports =
    mongoose.models.Customer || mongoose.model('Customer', customerSchema);

Upvotes: 1

ant
ant

Reputation: 21

Deleting the /dist folder did the trick for me after I tried almost every other solution

Upvotes: 0

mrin
mrin

Reputation: 1

This solution works well, but has the problem that type information of the schema is lost.

export default mongoose.models.Users || mongoose.model("Users", UsersSchema);

so I found this elegant solution.

export default mongoose.models.Users as unknown as null ?? model("Users", UsersSchema)

from here. https://qiita.com/mrin/items/43fb1c703f6f5a0ff56c

Upvotes: 0

Rahul Nikam
Rahul Nikam

Reputation: 31

Make sure you write correct syntax, for eg

Wrong syntax

export default mongoose.model.Users || mongoose.model("Users", UsersSchema);

Right syntax

export default mongoose.models.Users || mongoose.model("Users", UsersSchema);

I have seen many people writes mongoose.model instead of mongoose.models before the OR || operator

Upvotes: 0

Nean
Nean

Reputation: 1

if the error still persists, add this line to your code inside your models/[your_model].js

delete mongoose.connection.models['your_model'];

This will remove the Product model from the Mongoose model cache, allowing you to redefine it.

Upvotes: 0

Fajer alhamad
Fajer alhamad

Reputation: 1

mongoose.models = {}

THIS Solution is solved my problem

Upvotes: 0

lestonz
lestonz

Reputation: 149

If you have overWrite problem. You should make check the models.

let User

if (mongoose.models.User) {
    User = mongoose.model('User')
} else {
    User = mongoose.model('User', userSchema)
}

Upvotes: 2

Lord Ogaga
Lord Ogaga

Reputation: 1

In my case, i had file structure like this
Modules
-> User
   ->controllers
   ->models
      ->user.model.js
      ->userDetails.model.js
   ->Repository
      ->user.repository.js
      ->userdetails.repository.js
-> Posts
   // same as model

In my repository folder I referenced model like so

      const User = require("../models/user.model") 

but this yelled at me.
All I did to solve this was give a reference of 

    const User = require("../../User/models/user.model")

This solved the problem.. 
happy Hacking

Upvotes: 0

Anshuman Bisoyi
Anshuman Bisoyi

Reputation: 236

var user = mongoose.model('users', {});

Here, in both places, you have used 'users' which is identical so it's a conflict and therefore one cannot overwrite another. To fix this, change them.

Upvotes: 0

Haneen
Haneen

Reputation: 1146

As per the answer: https://stackoverflow.com/a/34291140/17708926, it fixes this issue partially but also raises another error in the code.

Error

The fix to this problem can be obtained by exporting a new model if it doesn't exist, I know this was the same idea in that answer but now it's implemented differently.

/// ... your schema

const model = mongoose.models.Model || mongoose.model("Model", modelSchema);

export default model;

Upvotes: 1

The Codepreneur
The Codepreneur

Reputation: 244

A solution that worked for me was just to check if an instance of the model exists before creating and exporting the model.

import mongoose from "mongoose";
const { Schema } = mongoose;
const mongoosePaginate = require("mongoose-paginate");

const articleSchema = new Schema({
  title: String, // String is shorthand for {type: String}
  summary: String,
  data: String,
  comments: [{ body: String, date: Date }],
  date: { type: Date, default: Date.now },
  published: { type: Boolean, default: true },
  tags: [{ name: String }],
  category: String,
  _id: String,
});


const Post = mongoose.models.Post ? mongoose.models.Post : mongoose.model("Post",articleSchema);

export default Post;

Upvotes: 2

Edio Paulo
Edio Paulo

Reputation: 1

If you are using Serverless offline one of these should do the trick

--skipCacheInvalidation

or

--useSeparateProcesses

especially this current one

--useChildProcesses

Upvotes: 0

Ankrah Solomon
Ankrah Solomon

Reputation: 21

Make sure you are not using the same model name for two different schemas.

Example:

// course model
const mongoose = require("mongoose");
const courseSchema = new mongoose.Schema({
    course: {
        type: String,
        required: true,
    },
    course_category: {
        type: String,
        required: true,
    }
});
module.exports = mongoose.model("course", courseSchema);

// student model
const mongoose = require("mongoose");
const studentSchema = new mongoose.Schema({
    first_name: {
        type: String,
        required: true,
    },
    last_name: {
        type: String,
        required: true,
    }
});
module.exports = mongoose.model("course", studentSchema);

Upvotes: 1

Punit Kashyap
Punit Kashyap

Reputation: 9

Adding this line will 100% solve your error.

mongoose.models = {}

Upvotes: 0

Jakub A Suplicki
Jakub A Suplicki

Reputation: 4801

Below is the full solution to similar problem when using Mongoose with Pagination in combination with Nuxt and Typescript:

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

import { default as mongoosePaginate } from 'mongoose-paginate-v2';

export interface IUser extends Document {
    name: string;
}

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

UserSchema.plugin(mongoosePaginate)

interface User<T extends Document> extends PaginateModel<T> {}


const User: User<IUser> = models['User'] as User<IUser> || model<IUser>('User', UserSchema) as User<IUser>;

export default User

tsconfig.json:

{
    "compilerOptions": {
        "target": "ES2018",
        "module": "ESNext",
        "moduleResolution": "Node",
        "lib": ["ESNext", "ESNext.AsyncIterable", "DOM"],
        "esModuleInterop": true,
        "allowJs": true,
        "sourceMap": true,
        "strict": true,
        "noEmit": true,
        "baseUrl": ".",
        "paths": {
            "~/*": ["./*"],
            "@/*": ["./*"]
        },
        "types": ["@types/node", "@nuxt/types"]
    },
    "exclude": ["node_modules"]
}

To make pagination working you will also need to install @types/mongoose-paginate-v2


The above solution should also deal with problems related to hot reloading with Nuxt (ServerMiddleware errors) and pagination plugin registration.

Upvotes: 2

ABHIJEET KHIRE
ABHIJEET KHIRE

Reputation: 2471

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const userSchema = new Schema({
    name: String,
});

// Trying to get the existing model to avoid OverwriteModelError
module.exports = mongoose.model("user") || mongoose.model('user', userSchema);

Upvotes: 3

Rishabh
Rishabh

Reputation: 161

Click here! Official example. Most important! thing is to export like this

export default mongoose.models.Item || mongoose.model('Item', itemsSchema)

Upvotes: 15

Mayukh Chakraborty
Mayukh Chakraborty

Reputation: 175

I faced the same Issue with NextJS and MongoDB atlas. I had a models folder with the model of session stored, but the problem was not that I defined the Schema twice.

  1. Make sure the Collection is empty and does not have a previous Document
  2. If it does, then Simply declare a Model without Schema, like this:
const Session = mongoose.model("user_session_collection")
  1. You can delete the previous records or backup them, create the schema and then apply query on the database.

Hope it helped

Upvotes: 2

Mans
Mans

Reputation: 3261

I faced this issue using Next.js and TypeScript. The top answers made it such that typings would not work.

This is what works for me:

const { Schema } = mongoose

export interface IUser {
  name: string
  email: string
}

const UserSchema = new Schema<IUser>({
  name: { type: String, required: true },
  email: { type: String, required: true },
})

const UserModel = () => mongoose.model<IUser>('User', UserSchema)

export default (mongoose.models.User || UserModel()) as ReturnType<
  typeof UserModel
>

Upvotes: 4

jonnie
jonnie

Reputation: 12690

Another reason you might get this error is if you use the same model in different files but your require path has a different case.

For example, in my situation I had require('./models/User') in one file, and then in another file where I needed access to the User model, I had require('./models/user').

I guess the lookup for modules & mongoose is treating it as a different file. Once I made sure the case matched in both it was no longer an issue.

Upvotes: 313

afshar003
afshar003

Reputation: 839

ther are so many good answer but for checking we can do easier job. i mean in most popular answer there is check.js ,our guy made it so much complicated ,i suggest:

function connectToDB() {
  if (mongoose.connection.readyState === 1) {
    console.log("already connected");
    return;
  }
  mongoose.connect(
    process.env.MONGODB_URL,
    {
      useCreateIndex: true,
      useFindAndModify: false,
      useNewUrlParser: true,
      useUnifiedTopology: true,
    },
    (err) => {
      if (err) throw err;
      console.log("DB connected");
    },
  );
}

readyState== 1 means connected
so does not try to connect again
so you won't get the error
i think it because of connecting while it is connected
it is another way of connecting to db

Upvotes: 1

Khan Abu Talha
Khan Abu Talha

Reputation: 11

just export like this exports.User = mongoose.models.User || mongoose.model('User', userSchema);

Upvotes: 1

Jack
Jack

Reputation: 69

Here is one more reason why this can happen. Perhaps this can help someone else. Notice the difference, Members vs Member. They must be the same...

export default mongoose.models.Members || mongoose.model('Member', FamilySchema)

Change to:

export default mongoose.models.Member || mongoose.model('Member', FamilySchema)

Upvotes: 6

Mike K
Mike K

Reputation: 6491

What you can also do is at your export, make sure to export an existing instance if one exists.

Typescript solution:

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

Upvotes: 4

Justin Herrera
Justin Herrera

Reputation: 653

This may give a hit for some, but I got the error as well and realized that I just misspelled the user model on importing.

wrong: const User = require('./UserModel'); correct: const User = require('./userModel');

Unbelievable but consider it.

Upvotes: 5

user10261767
user10261767

Reputation:

I solved this issue by doing this

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

const Schema = mongoose.Schema;

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

Then in other files

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

Better Solution

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

I hope this helps...

Upvotes: 2

AKP
AKP

Reputation: 42

Since this issue happened because calling model another time. Work around to this issue by wrapping your model code in try catch block. typescript code is like this -

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

Similarly you can write code in js too.

Upvotes: 0

Related Questions