node.jsmongodbexpressnext.jsmongoose-schema

"Cannot overwrite model once compiled" Next.js and Mongoose Schemas


First time using Next.js, I'm trying to implement a Node.js server with MongoDB database, schema models and routes.

I'm not sure what I'm doing wrong, since I tried a lot of combinations, as you can see in the comments in my code. I need to use the models but I'm getting the following error:

"OverwriteModelError: Cannot overwrite termscon model once compiled."

server/models/TermsCon.js:

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

// Create Schema
const TermsConSchema = new Schema({
    _id: {
        type: String,
        required: true,
        default: "1"
    },
    text: {
        type: String,
        required: true,
        default: "Lorem Ipsum"
    }
});

// const TermsCon = mongoose.model.termscon || mongoose.model('termscon', TermsConSchema);    
// module.exports = TermsCon;

// module.exports = mongoose.model('termscon', TermsConSchema);
// export default mongoose.model.TermsCon || mongoose.model('termscon', TermsConSchema)
module.exports = TermsCon = mongoose.model('termscon', TermsConSchema);

server/routes/api/termscons.js:

const express = require('express')
const mongoose = require('mongoose');
const router = express.Router()

const TermsCon = require('../../models/TermsCon')
// const TermsCon = mongoose.model('termscon')

router.get('/', (req, res) => {
    TermsCon.find()
    .then(tc => {
        res.json(tc)
    })
});

module.exports = router;

server/index.js:

const express = require('express')
const next = require('next')
const mongoose = require('mongoose')

const port = process.env.PORT || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare().then(() => {
    
    mongoose
    .connect(process.env.MONGODB_URI,
        {
            useNewUrlParser: true,
            useUnifiedTopology: true,
            useNewUrlParser: true,
            useUnifiedTopology: true,
            useCreateIndex: true
        }
    )
    .then(() => console.log('MongoDB Connected...'))
    .catch(err => console.log(err));    

    const server = express()

    server.use("/api/termscons", require("./routes/api/termscons"))

    server.get('*', (req, res) => {
        return handle(req, res)
    })

    server.listen(port, (err) => {
        if (err) throw err
        console.log(`Server started on port ${port}`)
    })
})

pages/index.js:

import axios from 'axios'
import { useState, useEffect } from 'react'

export default function Home() {     

    const [ tc, setTc ] = useState()
    
      useEffect(() => {
        axios.get('/api/termscons')
          .then(res => {
            setTc(res.data)
          })
          .catch(err =>console.log("ERR: ", err))    
      }, [])
      
      return (
            <div>
              {tc ?
                <p>{tc}</p>
              : null}
            </div>
      )
    }

Is it something wrong with the way I'm exporting my schema? With the way I'm connecting to my MongoDB? The routes? Pages?

Any idea will be much appreciated! Thanks!


Solution

  • So I changed the structure:

    1. I gave up creating a custom server since it didn't helped me at all in my Next.js app. So I don't have any server/index.js anymore or server/routes/api. Actually, there is no "server" folder at all. I simply created a mongodb connection separatelly to help me connect to my database, wich I call at each server api call, like so:

    utils/dbConnect.js:

    import mongoose from 'mongoose'
    
    async function dbConnect() {
      await mongoose.connect(process.env.MONGODB_URI, {
        useNewUrlParser: true,
        useUnifiedTopology: true,
        useFindAndModify: false,
      })
    }
    
    export default dbConnect
    
    1. Since I don't have a custom server anymore, I don't have server/routes/api either. So for the api routes I use the default next.js api folder:

    pages/api/termscons.js:

    import dbConnect from '../../../utils/dbConnect'
    import TermsCon from '../../../models/TermsCon'
    
    export default async function handler(req, res) {
      await dbConnect()
    
      switch (req.method) {
        case 'GET':
          try {
            const tc = await TermsCon.find()
            res.status(200).json(tc)
          } catch (error) {
            res.status(400).json({ itemnotfound: "No item found" })
          }
          break
        default:
          res.status(400).json({ itemnotfound: "No item found" })
          break
      }
    }
    
    1. To conclude, I have a folder with all my models in my app main folder:

    models/TermsCon.js:

    import mongoose from 'mongoose'
    
    const TermsConSchema = new mongoose.Schema({
        _id: {
            type: String,
            required: true,
            default: "1"
        },
        text: {
            type: String,
            required: true,
            default: "Lorem Ipsum"
        }
    });
    
    export default mongoose.models.TermsCon || mongoose.model('termscon', TermsConSchema);