Search code examples
node.jsmongodbmongoosemongoose-schema

Mongoose save() - inside a wrapper function - return document gives depreciation warning


My code is like this:

const mongoose = require('../common/mongoose.service').mongoose;

//..     
//.. schema definition here..
//.. 

//-- create the model
const Student = mongoose.model('Student', studentSchema);

//-- delete "__v" field
studentSchema.set('toJSON', {
    getters: true,
    transform: (doc, ret) => {    
      delete ret.__v;
      return ret;
    },
});

exports.createStudent = (studentData) => {
    const student = new Student(studentData);
    return student.save();
};

And it was giving me the _id when I call this createStudent() method from my Student controller.

Now I was trying to get the inserted document, updated my code like this:

exports.createStudent = (studentData) => {
    const student = new Student(studentData);
    return student.save().then( s => { return s } ).catch( err => console.log(err) );
};

Package versions:

"mongoose": "^5.9.23",
"mongoose-sequence": "^5.2.2",

My questions:

  1. My Visual Studio Code editor suggests me to make this createStudent asynchronous. Is it needed?
  2. The code that I added for deleting the "_v" field doesn't seem to be work in the above return. I mean inside the then() of save() method

Solution

  • You need a little bit of refactoring here. Either you directly return the promise from the method or execute it and resolve the value as promise value.

    exports.createStudent = (studentData) => {
        const student = new Student(studentData);
        return student.save().then( s => { return s } ).catch( err => console.log(err) );
    };
    

    In the above code, you have a return statement as well as then/catch, it turns out that while it is saving the user with User.save() which is asynchronous, your return doing an explicit return and in this case it would `undefined.

    As mongoose returns promise for the save method,either you just call it like this

    // return a promise here
    exports.createStudent = (studentData) => {
      const student = new Student(studentData);
      return student.save()
    };
    

    Wherever you call the createStudent() meaning a controller/service, just use then and catch or use async/await. Let assume we're calling it in the following function.

    function execute() {
      createStudent({fname:'john', lname: 'doe'}).then(res => {
        console.log("student: ", student);
      }).catch(err => {
        console.log(err);
        //handle error
      })
    }
    

    Or simply use async await to make it even more simpler

    async function execute() {
      try {
        let student = await createStudent({fname:'john', lname: 'doe'});
        console.log("student: ", student);
    
      } catch(err) {
        // handle error
      }
    }
    

    To answer your second question, I am not sure whether we can use userSchema.set to override the toJSON, But I tried the following and it seems to be working as expected for me.

    Here is a User model. Do note that the toJSON is inside the model property and I am deleting __v and _id properties here.

    var mongoose = require('mongoose');
    var Schema = mongoose.Schema;
    var userSchema = new Schema({
        name: {
            type: String,
            required: true,
            maxlength: 30,
            trim: true
        },
        role: {
            type: Number,
            default: 0
        },
        todos: [{
            type: Schema.Types.ObjectId,
            ref: "Todo"
        }]
    }, {
        toJSON: {
            getters: true,
            transform: function(doc, ret) {
                delete ret._id;
                delete ret.__v
            }
        }
    });
    module.exports = mongoose.model("User", userSchema)
    

    I have a user/ which simply fetches all the user from my DB and it returns exactly the kind of response I am looking for, no __v and _id properties in it.

    enter image description here