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

标签 javascript node.js mongodb express mongoose

我要完成的事情的简要概述:

在前端,用户可以使用表单编辑有关其帐户的信息。然后无论有多少字段被编辑/触摸,该表单都会发送到相同的 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'});
                    }
                });
            }
        });
    }
});

如果这对某些人来说似乎显而易见,我深表歉意。我仍在学习并且不确定如何处理这个问题。谢谢

最佳答案

实际上不需要在此处进行多次调用,或者几乎没有任何效率。您无需进行多次调用,而是根据所选选项构建查询和更新。

也完全没有必要构造不同的方法来修改每个属性。如果表达正确,标准的 mongoose(实际上是 MongoDB)方法应该足以描述预期的功能。不这样做既麻烦又不切实际,构建查询选项而不是特定的属性调用是您通常要做的:

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

  });

});

因此,无需分支并进行不同的调用,您只需检查提供的选项并从那里构建查询和更新语句。这些只是常规对象表示的“设计”,就像任何对象一样,您只需操纵结构来构造它们。

这里的第一个主要区别是使用查询来“检查目标值是否存在”以进行更改。那真的很低效。您真正要求的是这些值是“唯一的”,以便集合中的其他对象不能共享相同的 nameemail。您强制执行此操作的方式是使用“索引”:

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

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

这就是代码所做的,通过测试返回的错误代码并在它被识别为重复键错误时给出适当的响应消息:

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

这比进行单独的查询来测试目标值是否已经存在要直接得多。它也更可靠,因为在您的“查询”和当前代码中的后续“更新”之间,其他东西可能实际上会更改数据。因此,如果不强制执行唯一索引并检查错误,您就有创建重复项的风险。因此,为正确的工作使用正确的工具。

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

至于消息本身,您可以“按原样”保留它们,我个人认为这是完全合理的,或者您也可以在请求参数上交替使用与语句构造类似的分支逻辑来确定要返回的具体消息内容.

举个例子:

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

希望您能大致了解。

但这比尝试将不同的调用链接在一起并在您确实不需要时发出多个请求要好得多。


作为旁注,我们实际上有比使用回调嵌套更现代和推荐的处理方式。 Promises 已经存在了一段时间,您也确实应该在支持 async 的环境中工作/await语法,就像任何 nodejs v8.x.x 版本一样,实际上即将成为长期支持 (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 });
    }
  }
});

当您确实有一系列异步函数要解析时,它就真正发挥了作用,而我们在这种情况下真正想要避免的是。但一般情况下甚至包括 try..catch block 至少有一个更合乎逻辑的流程,并且确实提高了代码的可读性。

关于javascript - 在同一个请求中进行两个方法调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46028708/

相关文章:

node.js - Mongoose 分页不区分大小写的字符串排序

JavaScript 超时

javascript - 如何从 vkontakte 获取长期访问 token ?

javascript - 模块 dotenv 仅用于开发吗?

javascript - 如何从连接回调之外的应用程序中的任何位置发出套接字?

node.js - mongodb中通过binData类型上传小文件

java - 无法从 MongoDB 中的文档数组中删除最低分数

javascript - 带有 three.js 的简单太阳系

javascript - 使用 JavaScript 查找 CSS Float

javascript - 使用 Typescript 声明了一个类型,但 Javascript 在内部使用了错误的类型