Javascript 如何从mongoose+;表达
我用mongoose和express 3创建了一个注册表单 用户可能已经存在该用户名,在这种情况下,我会得到一个err.code 11000(重复密钥)。我应该如何处理现有用户 这就是我现在正在做的…但我不确定检查错误代码是最好的方法:Javascript 如何从mongoose+;表达,javascript,node.js,express,mongoose,Javascript,Node.js,Express,Mongoose,我用mongoose和express 3创建了一个注册表单 用户可能已经存在该用户名,在这种情况下,我会得到一个err.code 11000(重复密钥)。我应该如何处理现有用户 这就是我现在正在做的…但我不确定检查错误代码是最好的方法: user.save(function(err){ if ( err ) { console.log(err); console.log(err.code); //duplicate key if (
user.save(function(err){
if ( err ) {
console.log(err);
console.log(err.code);
//duplicate key
if ( err.code == 11000 ) {
req.flash('error', 'User already exists');
res.redirect('/signup');
return;
}
}
res.locals.user = user;
req.session.user = user;
//res.locals.session = req.session;
res.redirect('/');
});
有更好的方法吗?试试这个:
user.save(function(err){
if ( err && err.code !== 11000 ) {
console.log(err);
console.log(err.code);
res.send('Another error showed up');
return;
}
//duplicate key
if ( err && err.code === 11000 ) {
req.flash('error', 'User already exists');
res.redirect('/signup');
return;
}
res.locals.user = user;
req.session.user = user;
//res.locals.session = req.session;
res.redirect('/');
});
您不会以这种方式填写错误日志。我还没有尝试过这种方法,但我认为这样可以避免导致错误:
//look for existing user first
user.findOne({ username: req.body.username }, function(err, user) {
if ( err ) throw err;
//existing user found, stop registration
if ( user ) {
res.flash('error', "That user already exists");
res.redirect('/signup');
return;
}
//create new user
var user = new User({ username: req.body.username });
user.save(function(err){
if ( err ) throw err;
res.flash('info', "Your account has been created");
res.redirect('/account');
});
});
最简单的方法是使用逻辑方法
var someschema = Schema({
num: {type:Number,unique:true} // increment number
});
var someModal = mongoose.model('someschema', someschema);
async function insertDoc(someModal, lastNumFromDb, newDocToSave) {
try {
let lastNumFromDb = await someModal.findOne().sort({ _id: -1 }).lean();
newDocToSave.lastNumFromDb = lastNumFromDb + 1
let saved = await new someModal(newDocToSave).save();
return saved;
} catch (err) {
if (err.code === '11000') {
return insertDoc(someModal, lastNumFromDb, newDocToSave)
}else{
throw err
}
}
}
controller.js
var someschema = Schema({
num: {type:Number,unique:true} // increment number
});
var someModal = mongoose.model('someschema', someschema);
async function insertDoc(someModal, lastNumFromDb, newDocToSave) {
try {
let lastNumFromDb = await someModal.findOne().sort({ _id: -1 }).lean();
newDocToSave.lastNumFromDb = lastNumFromDb + 1
let saved = await new someModal(newDocToSave).save();
return saved;
} catch (err) {
if (err.code === '11000') {
return insertDoc(someModal, lastNumFromDb, newDocToSave)
}else{
throw err
}
}
}
如果你在2021年来这里,我写了一篇关于这个的文章
您基本上覆盖了
create
或insertOne
函数,并在发生错误之前通过indexscan处理错误。看起来非常干净。你对此有什么特别不满意的地方?只是我让数据库抛出了一个错误,而不是先检查用户。这取决于什么能让另一个解决方案在你的情况下成为“更好的方式”。这并不难,但如果这在功能上是正确的,并且它的性能是足够的,并且它是可维护的…?我不想用重复的密钥错误填充错误日志。这不是我所拥有的吗?有什么区别。不管怎样,错误都会出现在日志中…不知道这有什么不同。抱歉@chovy,修改了我的答案一点。-如果错误不是“重复密钥”错误,则会出现第一个条件,并向客户端返回“出现另一个错误”。-如果错误是“重复密钥”错误,则将发生第二个条件错误。-如果没有错误,脚本将按照指示运行。我明白了——谢谢。但我仍然认为会记录错误,因为查询抛出了一个错误。我可以执行user.findOne(..,函数(err,user){if(!user)new user();user.save()});您还可以使用.count()
,这稍微简洁一些,但不允许在需要时使用返回的数据。Ps,我确实认为mongoose应该有类似Model.saveUnique({username:req.body.username},function(err){…})的内容
处理重复键错误实际上更安全,因为在user.findOne()
读取集合和执行user.save()
之间,另一个请求可能创建了用户。也就是说,存在一种竞争条件,在这种情况下,API可能抛出5xx错误。对于希望用户不存在的表单,只需尝试保存它,然后处理预期的DuplicateKey错误,代码就更少了(不需要user.findOne()
),并避免了这种竞争条件。如果您希望实体已经存在,那么首先尝试加载它可能更自然。