Search code examples
node.jsmongodbexpresspassport.jspassport-local

Issue in saving registered user to MongoDB in Node JS - Express application


I am new to Node.js and trying to create a chat application program. For that I have created a Signup registration form with express framework. The data will be saved in MongoDB. Application uses passport middleware signup functionality. Issue is when submitting a new user for second time I am not able to see the data in mongoDB, instead i can see only the first data. I set the mongodb debug option to true, after submitting the form, user submitted data will be seen through console.

Please see the github code which i created: https://github.com/Deepesh316/jabarchat

Please see the mongodb user details getting saved data code: passport-local.js

passport.use('local.signup', new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password',
    passReqToCallback: true
}, (req, email, password, done) => {
    User.findOne({'email': email}, (err, user) => {

        // Network or Internet connection error
        if(err) {
            return done(err);
        }

        if(user) {
            return done(null, false, req.flash('error', 'User with email already exist'));
        }

        // Creating new instance of user and save it to database

        const newUser = new User();
        newUser.username = req.body.username;
        newUser.email = req.body.email;
        newUser.password = newUser.encryptPassword(req.body.password);

        newUser.save((err) => {
            done(null, newUser);
        });
    });
}));

Below is the code snippet for Model:

const mongoose = require('mongoose');
const bcrypt = require('bcrypt-nodejs');

const userSchema = mongoose.Schema({
    username: { type: String, unique: true },
    fullname: { type: String, unique: true, default: ''},
    email: { type: String, unique: true },
    password: { type: String, default: ''},
    userImage: { type: String, default: 'default.png'},
    facebook: { type: String, default: ''},
    fbTokens: Array,
    google: { type: String, default: ''},
    googleTokens: Array
});

userSchema.methods.encryptPassword = function(password) {
    return bcrypt.hashSync(password, bcrypt.genSaltSync(10), null);
};

userSchema.methods.validUserPassword = function(password) {
    return bcrypt.compareSync(password, this.password);
};

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

Solution

  • The error message is saying that there's already a record with null as the fullname. In other words, you already have a user without an fullname.

    The relevant documentation for this:

    If a document does not have a value for the indexed field in a unique index, the index will store a null value for this document. Because of the unique constraint, MongoDB will only permit one document that lacks the indexed field. If there is more than one document without a value for the indexed field or is missing the indexed field, the index build will fail with a duplicate key error.
    
    You can combine the unique constraint with the sparse index to filter these null values from the unique index and avoid the error.
    
    
    Sparse indexes only contain entries for documents that have the indexed field, even if the index field contains a null value.
    

    In other words, a sparse index is ok with multiple documents all having null values.

    Check with mydb.users.getIndexes() if this is the case and manually remove the unwanted index with mydb.users.dropIndex()