在同一请求中进行两个方法调用

简要介绍一下我正在努力完成的工作:

在前端,用户能够使用表格编辑关于他们的账户的信息。 然后,不pipe有多less个字段被编辑/触摸,该表单都被发送到相同的HTTP请求。

我的想法是,请求会处理哪些字段进行编辑。 除了我不确定如何返回确认数据外,这种逻辑似乎对我来说很有用。 例如,如何知道所有请求何时完成/要显示哪些确认和错误消息。

//Change information route router.post('/changeinformation', passport.authenticate('jwt', {session: false}), (req, res, next) => { const changeInfo = { changeEmail: req.body.changeEmail, changeUsername: req.body.changeUsername }; if(changeInfo.changeUsername === true) { const userInfo = { email: req.body.email, currentEmail: req.body.currentEmail }; Artist.getArtistByEmail(userInfo.email, (err, user) => { if (err) throw err; if (user) { return res.json({success: false, msg: 'Email already exists'}); } else { Artist.changeEmail(userInfo, (err, callback) => { if (callback) { console.log(callback); return res.json({success: true, msg: 'Email has been changed successfully'}); } }); } }); } if(changeInfo.changeUsername === true) { //Checks if username exists const nameInfo = { name: req.body.name, currentName: req.body.currentName }; Artist.getArtistByName(userInfo.name, (err, user) => { if (err) throw err; if (user) { return res.json({success: false, msg: 'Name already exists'}); } else { Artist.changeName(userInfo, (err, callback) => { if(callback) { console.log(callback); return res.json({success: true, msg: 'Name has been changed successfully'}); } }); } }); } }); 

我很抱歉,如果这似乎是显而易见的一些。 我仍然在学习,不确定如何处理这个问题。 谢谢

在这里打多个电话真的不需要,或者任何接近效率的地方。 您可以根据选定的选项构build查询和更新,而不是进行多个呼叫。

构build不同的方法来修改每个属性也是完全没有必要的。 如果expression正确,标准mongoose(实际上是真正的MongoDB)方法应该足够描述预期的function。 否则做起来麻烦而且不切实际,build立查询选项而不是特定的属性调用是你通常要做的事情:

 router.post('/changeinformation', passport.authenticate('jwt', {session: false}), (req, res) => { let query = { }, update = { $set: { } }; if ( req.body.changeEmail ) { query['email'] = req.body.currentEmail; // presuming this is current update.$set['email'] = req.body.email; } if ( req.body.changeUsername ) { query['name'] = req.body.currentName; update.$set['name'] = req.body.name; } // One call only User.update(query,update,(err,result) => { if (err) { if (err.code === 11000) { // Duplicate key error res.json({ success: false, msg: 'email or name already exists' }); } else { res.json({ success: false, msg: err.message }); } } else { if ( result.n === 0 ) { res.json({ success: false, msg: 'Requested details not found' }); } else { res.json({ success: true, msg: 'Details updated successfully' }); } } }); }); 

因此,不要分支并进行不同的调用,只需检查提供的选项并从那里构build查询和更新语句。 这些是“通过devise”只是普通的对象表示,就像任何对象一样,您只需简单地操纵结构来构build它们。

这里的第一个主要出发点是使用查询来检查变化的“目标值的存在性”。 这真的很低效。 你真正要求的是,这些值而不是“唯一的”,以便集合中的其他对象不能共享相同的nameemail 。 你强制执行的方式是使用“索引”:

 const userSchema = new Schema({ ... email: { type: String, required: true, unique: true }, name: { type: String, required: true, unique: true } ... }); 

模式中的那些"unique"属性告诉mongoose在该属性上创build一个“唯一”的索引。 如果您尝试在集合中添加多个相同的值(即,将用户名更改为与现有条目相同的值),则会抛出一个“重复键错误”,我们可以通过错误代码捕获该错误做出相应回应

所以这就是代码所做的事情,通过testing返回的错误代码,并在被识别为重复键错误时给出相应的响应消息:

  if (err.code === 11000) { res.json({ success: false, msg: 'email or name already exists' }); } else { res.json({ success: false, msg: err.message }); } 

这比直接testing目标值是否已经存在更为直接。 而且它更可靠,因为在你的“查询”和当前代码中的后续“更新”之间,其他的东西实际上可以改变数据。 因此,如果不执行唯一索引并检查错误,则可能会造成重复的风险。 所以使用正确的工具来完成正确的工作。

另一个在这里检查当然是看是否有任何事情与更新相匹配。 它始终包含在n属性下的.update()响应对象中,该属性表示条件实际匹配的文档数量。

至于消息本身,你可以把它们保持原样,我个人觉得这是完全合理的,或者你可以在请求参数中使用类似的分支逻辑,就像语句结构一样,决定返回的具体消息内容。

举个例子:

 let errStr = (req.body.changeEmail && req.body.changeUsername) ? "email or name" : ( req.body.changeEmail ) ? "email" : "name"; res.json({ success: false, msg: `${errStr} already exists` }); 

希望你能得到大概的想法。

但是,比起试图将不同的呼叫连接在一起,并且在你不需要的时候提出多个请求,情况要好得多。


作为一个旁注,我们实际上有比使用callback嵌套更现代和推荐的方式来处理事情。 承诺已经存在一段时间了,你也应该在一个支持async / await语法的环境中工作,因为任何nodejs v8.xx版本都会这样做,而且实际上它将成为长期支持(LTS)版本:

 router.post('/changeinformation', passport.authenticate('jwt', {session: false}), async (req, res) => { let query = { }, update = { $set: { } }; if ( req.body.changeEmail ) { query['email'] = req.body.currentEmail; // presuming this is current update.$set['email'] = req.body.email; } if ( req.body.changeUsername ) { query['name'] = req.body.currentName; update.$set['name'] = req.body.name; } try { let result = await User.update(query,update); if ( result.n === 0 ) { let msgStr = (req.body.changeEmail && req.body.changeUsername) ? "email or name" : ( req.body.changeEmail ) ? "email" : "name"; res.json({ success: false, msg: `Requested ${msgStr} not found` }); } else { res.json({ success: true, msg: 'Details updated successfully' }); } } catch(e) { if (e.code === 11000) { let errStr = (req.body.changeEmail && req.body.changeUsername) ? "email or name" : ( req.body.changeEmail ) ? "email" : "name"; res.json({ success: false, msg: `${errStr} already exists` }); } else { res.json({ success: false, msg: e.message }); } } }); 

当你确实有一系列的asynchronous函数来解决这个问题的时候,它真的进入了它自己,以及在这种情况下我们真的试图避免的东西。 但是,即使包含try..catch块的一般情况也至less有一个更合理的stream程,并提高了代码的可读性。

第一个if(changeInfo.changeUsername === true)应该是if(changeInfo.changeEmail === true)跟随你的逻辑。