Search code examples
mongodbmongoosemongoose-schemamongodb-shellmongoose-models

I am not being able to create document in mongoDB server using mongoose?


I am not being able to create document properly using mongoose in my locally deployed mongodb server. Only id is being created not the full data(name , email , password) I sent. In server the data looks like this{ "_id": { "$oid": "651d8f91c018db3d9504da2a" }, "__v": 0 } Mongosh shell and MongoDB compass is working fine though. But mongosh shell giving this warning : Access control is not enabled for the database. . Idk if that is a problem here or not.

schema:

const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
    name : {type: String , 
        required: true 
    },
    email : {type: String ,
        required: true 
       },
    password : {type: String ,
         required: true 
        },
}, {timestamps: true});

module.exports = mongoose.model('user', userSchema);

HTML:

<div class="loginform">
      <div class="login">
        <label for="name">Name</label><input type="text" id="name" />
      </div>
      <div class="login">
        <label for="email">Email</label><input type="text" id="email" />
      </div>
      <div class="login">
        <label for="password">Password</label
        ><input type="text" id="password" />
        <button id="signinbutton">Create Account</button>
      </div>
    </div>

post request front

async function postData(url = "", data = {}) {
        const response = await fetch(url, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(data),
        });
        let rdata = await response.json()
        return rdata
      };

      let submit = document.getElementById("signinbutton")
      submit.addEventListener("click", async() => {
        let name = document.getElementById("name").value
        let email = document.getElementById("email").value
        let password = document.getElementById("password").value
        let resp= await  postData("/signin", { name, email, password })
        if(resp.success){
            alert("user created")
        }
       })

post request

const express = require('express');
const app = express();
const path = require('path');
const mongoose = require('mongoose');
var bodyParser = require('body-parser')
const postm = require('./models/post');
const User =  require('./models/User');
mongoose.connect('mongodb://127.0.0.1/blogbase');
app.use(express.json({extended:true}));
app.use(express.urlencoded({extended: true}));
app.use(express.static(path.join(__dirname, "static")));
 const port = 3000
 app.listen(port, () =>{
  console.log('app http://localhost:${port}')
});

 app.post('/signin', async(res,req) => {
  let user = await User.create(req.body)
  console.log(req.body)
  res.status(200).json({success: true, user: user })
});

The error

D:\webdevedu\LBLOG\node_modules\mongoose\lib\document.js:3166
    this.$__.validationError = new ValidationError(this);
                               ^

ValidationError: user validation failed: password: Path `password` is required., email: Path `email` is required., name: Path `name` is required.
    at Document.invalidate (D:\webdevedu\LBLOG\node_modules\mongoose\lib\document.js:3166:32)
    at D:\webdevedu\LBLOG\node_modules\mongoose\lib\document.js:2959:17
    at D:\webdevedu\LBLOG\node_modules\mongoose\lib\schematype.js:1368:9
    at process.processTicksAndRejections (node:internal/process/task_queues:77:11) {
  errors: {
    password: ValidatorError: Path `password` is required.
        at validate (D:\webdevedu\LBLOG\node_modules\mongoose\lib\schematype.js:1365:13)
        at SchemaType.doValidate (D:\webdevedu\LBLOG\node_modules\mongoose\lib\schematype.js:1349:7)
        at D:\webdevedu\LBLOG\node_modules\mongoose\lib\document.js:2951:18
        at process.processTicksAndRejections (node:internal/process/task_queues:77:11) {
      properties: {
        validator: [Function (anonymous)],
        message: 'Path `password` is required.',
        type: 'required',
        path: 'password',
        value: undefined
      },
      kind: 'required',
      path: 'password',
      value: undefined,
      reason: undefined,
      [Symbol(mongoose:validatorError)]: true
    },
    email: ValidatorError: Path `email` is required.
        at validate (D:\webdevedu\LBLOG\node_modules\mongoose\lib\schematype.js:1365:13)
        at SchemaType.doValidate (D:\webdevedu\LBLOG\node_modules\mongoose\lib\schematype.js:1349:7)
        at D:\webdevedu\LBLOG\node_modules\mongoose\lib\document.js:2951:18
        at process.processTicksAndRejections (node:internal/process/task_queues:77:11) {
      properties: {
        validator: [Function (anonymous)],
        message: 'Path `email` is required.',
        type: 'required',
        path: 'email',
        value: undefined
      },
      kind: 'required',
      path: 'email',
      value: undefined,
      reason: undefined,
      [Symbol(mongoose:validatorError)]: true
    },
    name: ValidatorError: Path `name` is required.
        at validate (D:\webdevedu\LBLOG\node_modules\mongoose\lib\schematype.js:1365:13)
        at SchemaType.doValidate (D:\webdevedu\LBLOG\node_modules\mongoose\lib\schematype.js:1349:7)
        at D:\webdevedu\LBLOG\node_modules\mongoose\lib\document.js:2951:18
        at process.processTicksAndRejections (node:internal/process/task_queues:77:11) {
      properties: {
        validator: [Function (anonymous)],
        message: 'Path `name` is required.',
        type: 'required',
        path: 'name',
        value: undefined
      },
      kind: 'required',
      path: 'name',
      value: undefined,
      reason: undefined,
      [Symbol(mongoose:validatorError)]: true
    }
  },
  _message: 'user validation failed'
}

Node.js v18.17.0
[nodemon] app crashed - waiting for file changes before starting...


Solution

  • The values of email, name and password are undefined when your mongoose model tries to create a new user. There are a few issues with your code that are causing this but it looks like the values are not being sent.

    Firstly, it's more semantic to actually use a form if you are going to be submitting form data. I can see you are using JS to get elements by their id but the <form> element already comes with a handy way of accessing each type of input anyway so just give each input a name attribute as well. I will explain. Update your HTML like so:

    <form name="loginform" action="/signin">
       <div class="login">
          <label for="name">Name</label>
          <input type="text" id="name" name="name">
       </div>
       <div class="login">
          <label for="email">Email</label>
          <input type="text" id="email" name="email">
       </div>
       <div class="login">
          <label for="password">Password</label>
          <input type="text" id="password" name="password">
          <button id="signinbutton">Create Account</button>
       </div>
    </form>
    

    Next, bind the addEventListener to the actual form and prevent it's default behaviour of automatically submitting. You also have no error handling for your fetch network requests so you don't know if your form is sending properly. Update like so:

    const form = document.querySelector('form[name="loginform"]')
    form.addEventListener('submit', (e)=>{
       e.preventDefault(); //< Prevent the form from submitting
       let name = form.elements.name.value; //< Get each input element
       let email = form.elements.email.value;
       let password = form.elements.password.value;
     
       fetch(form.action, { //< Now run fetch using form.action as url
          method: 'POST',
          body: JSON.stringify({ name, email, password }),
          headers: {
           'Content-type': 'application/json; charset=UTF-8',
          }
       })
       .then((response)=>{ 
          return response.json();
       })
       .then((data)=>{
          console.log(data);
          //Now handle a successful user creation 
       })
       .catch(error => {
          console.error('Error:', error)
          //Now handle an unsuccessful user creation 
       });
    });
    

    Your post route on the server looks OK but again you need to be able to catch any errors. I would suggest using try/catch like so and send the client an appropriate response on error:

    app.post('/signin', async(req, res) => {
       console.log(req.body); //< Make sure the form data has been parsed in req.body
       try{
          const {name, email, password} = req.body; //< Destructure only the values you need
          let user = await User.create({name, email, password});
          res.status(200).json({success: true, user: user });
       }catch(err){
          console.log(err);
          res.status(400).json({success: false, err: 'Appropriate error message' });
       }
    });
    

    The Access control is not enabled for the database is a warning and not an error. It is basically telling you that you haven't set-up user authentication. See how to do it here.

    Hope this helps and good luck with your project.