How to check if that data already exist in the database during update (Mongoose And Express) How to check if that data already exist in the database during update (Mongoose And Express) express express

How to check if that data already exist in the database during update (Mongoose And Express)


Typically you could use mongoose validation but since you need an async result (db query for existing names) and validators don't support promises (from what I can tell), you will need to create your own function and pass a callback. Here is an example:

var mongoose = require('mongoose'),    Schema = mongoose.Schema,    ObjectId = Schema.ObjectId;mongoose.connect('mongodb://localhost/testDB');var UserSchema = new Schema({    name: {type:String}});var UserModel = mongoose.model('UserModel',UserSchema);function updateUser(user,cb){    UserModel.find({name : user.name}, function (err, docs) {        if (docs.length){            cb('Name exists already',null);        }else{            user.save(function(err){                cb(err,user);            });        }    });}UserModel.findById(req.param('sid'),function(err,existingUser){   if (!err && existingUser){       existingUser.name = 'Kevin';       updateUser(existingUser,function(err2,user){           if (err2 || !user){               console.log('error updated user: ',err2);           }else{               console.log('user updated: ',user);           }       });   } });

UPDATE: A better way

The pre hook seems to be a more natural place to stop the save:

UserSchema.pre('save', function (next) {    var self = this;    UserModel.find({name : self.name}, function (err, docs) {        if (!docs.length){            next();        }else{                            console.log('user exists: ',self.name);            next(new Error("User exists!"));        }    });}) ;

UPDATE 2: Async custom validators

It looks like mongoose supports async custom validators now so that would probably be the natural solution:

    var userSchema = new Schema({      name: {        type: String,        validate: {          validator: function(v, cb) {            User.find({name: v}, function(err,docs){               cb(docs.length == 0);            });          },          message: 'User already exists!'        }      }    });


Another way to continue with the example @nfreeze used is this validation method:

UserModel.schema.path('name').validate(function (value, res) {    UserModel.findOne({name: value}, 'id', function(err, user) {        if (err) return res(err);        if (user) return res(false);        res(true);    });}, 'already exists');


In addition to already posted examples, here is another approach using express-async-wrap and asynchronous functions (ES2017).

Router

router.put('/:id/settings/profile', wrap(async function (request, response, next) {    const username = request.body.username    const email = request.body.email    const userWithEmail = await userService.findUserByEmail(email)    if (userWithEmail) {        return response.status(409).send({message: 'Email is already taken.'})    }    const userWithUsername = await userService.findUserByUsername(username)    if (userWithUsername) {        return response.status(409).send({message: 'Username is already taken.'})    }    const user = await userService.updateProfileSettings(userId, username, email)    return response.status(200).json({user: user})}))

UserService

async function updateProfileSettings (userId, username, email) {    try {        return User.findOneAndUpdate({'_id': userId}, {            $set: {                'username': username,                'auth.email': email            }        }, {new: true})    } catch (error) {        throw new Error(`Unable to update user with id "${userId}".`)    }}async function findUserByEmail (email) {    try {        return User.findOne({'auth.email': email.toLowerCase()})    } catch (error) {        throw new Error(`Unable to connect to the database.`)    }}async function findUserByUsername (username) {    try {        return User.findOne({'username': username})    } catch (error) {        throw new Error(`Unable to connect to the database.`)    }}// other methodsexport default {    updateProfileSettings,    findUserByEmail,    findUserByUsername,}

Resources

async function

await

express-async-wrap