Question Comment vérifier si ces données existent déjà dans la base de données lors de la mise à jour (Mongoose And Express)


Comment faire des validations avant de sauvegarder les données éditées dans mongoose?

Par exemple, si sample.name existe déjà dans la base de données, l'utilisateur recevra une sorte d'erreur, quelque chose comme ça, voici mon code ci-dessous

//Post: /sample/edit
app.post(uri + '/edit', function (req, res, next) {
  Sample.findById(req.param('sid'), function (err, sample) {

    if (err) {
      return next(new Error(err));
    }

    if (!sample) {
      return next(new Error('Invalid reference to sample information'));
    }

    // basic info
    sample.name = req.body.supplier.name;
    sample.tin = req.body.supplier.tin;

    // contact info
    sample.contact.email = req.body.supplier.contact.email;
    sample.contact.mobile = req.body.supplier.contact.mobile;
    sample.contact.landline = req.body.supplier.contact.landline;
    sample.contact.fax = req.body.supplier.contact.fax;

    // address info
    sample.address.street = req.body.supplier.address.street;
    sample.address.city = req.body.supplier.address.city;
    sample.address.state = req.body.supplier.address.state;
    sample.address.country = req.body.supplier.address.country;
    sample.address.zip = req.body.supplier.address.zip;

    sample.save(function (err) {
      if (err) {
        return next(new Error(err));
      }

      res.redirect(uri + '/view/' + sample._id);
    });

  });
});

17
2018-06-02 12:52


origine


Réponses:


Généralement, vous pouvez utiliser validation de la mangouste mais comme vous avez besoin d'un résultat asynchrone (requête db pour les noms existants) et que les validateurs ne prennent pas en charge les promesses (d'après ce que je peux dire), vous devrez créer votre propre fonction et passer un rappel. Voici un exemple:

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);
           }

       });
   } 
});

MISE À JOUR: Une meilleure façon

Le pré-crochet semble être un endroit plus naturel pour arrêter la sauvegarde:

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!"));
        }
    });
}) ;

MISE À JOUR 2: validateurs Async personnalisés

Il semblerait que mongoose supporte maintenant les validateurs asynchrones pour que ce soit probablement la solution naturelle:

    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!'
        }
      }
    });

43
2018-06-02 14:14



Une autre façon de continuer avec l'exemple @nfreeze utilisé est cette méthode de validation:

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');

5
2017-11-29 19:22



Voici une autre façon d’y parvenir en moins de code.

MISE À JOUR 3: Statique de la classe de modèle asynchrone

Semblable à l'option 2, cela vous permet de créer une fonction directement liée au schéma, mais appelée à partir du même fichier à l'aide du modèle.

model.js

 userSchema.statics.updateUser = function(user, cb) {
  UserModel.find({name : user.name}).exec(function(err, docs) {
    if (docs.length){
      cb('Name exists already', null);
    } else {
      user.save(function(err) {
        cb(err,user);
      }
    }
  });
}

Appeler depuis un fichier

var User = require('./path/to/model');

User.updateUser(user.name, function(err, user) {
  if(err) {
    var error = new Error('Already exists!');
    error.status = 401;
    return next(error);
  }
});

2
2018-03-18 18:06



Si vous effectuez une recherche avec un index unique, utiliser UserModel.count peut être plus avantageux que UserModel.findOne car il renvoie le document entier (c.-à-d. Une lecture) au lieu de renvoyer uniquement un int.


1
2017-07-27 05:33



En plus des exemples déjà affichés, voici une autre approche utilisant express-async-wrap et fonctions asynchrones (ES2017).

Routeur

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 methods

export default {
    updateProfileSettings,
    findUserByEmail,
    findUserByUsername,
}

Ressources

fonction asynchrone

attendre

express-async-wrap


1
2018-01-09 13:45