Выполнение двух вызовов метода в одном запросе

1

Краткий обзор того, что я пытаюсь выполнить:

В интерфейсе пользователь может редактировать информацию об их учетной записи с использованием формы. Затем эта форма отправляется на тот же 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'});
                    }
                });
            }
        });
    }
});

Прошу прощения, если это может показаться очевидным для некоторых. Я все еще учусь и не знаю, как справиться с этим. Спасибо

Теги:
express
mongoose

2 ответа

2
Лучший ответ

Сделать несколько вызовов здесь действительно не нужно, или где-нибудь рядом с эффективным. Вместо того, чтобы делать несколько вызовов, вы создаете запрос и обновляете в соответствии с выбранными параметрами.

Также совершенно необязательно создавать разные методы для изменения каждого свойства. При правильном выражении стандартные методы мангуста (на самом деле действительно 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' });
      }
    }

  });

});

Поэтому вместо того, чтобы разворачиваться и делать разные вызовы, вы просто проверяете предоставленные опции и создаете там запросы и обновления. Это "по-дизайн", просто регулярные представления объектов, и как любой объект, который вы просто манипулируете структурой для их построения.

Первым основным выходом здесь является использование запросов для "проверки существования целевых значений" для изменений. Это действительно неэффективно. То, что вы действительно просите, состоит в том, что эти значения вместо этого являются "уникальными", поэтому никакие другие объекты в коллекции не могут использовать одно и то же name или email. Как вы это применяете, используйте "индексы":

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

И, надеюсь, вы получите общую идею.

Но все это намного лучше, чем пытаться объединить разные вызовы и делать несколько запросов, когда вам это действительно не нужно.


В качестве побочного решения у нас есть более современные и рекомендуемые способы решения проблем, чем использование вложенных вызовов. Обещания существуют в течение некоторого времени, и вы также действительно должны работать в среде, поддерживающей синтаксис async/ await, как это делает любая версия nodejs v8.xx, и на самом деле это станет версией Long Term Support (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, по крайней мере, имеет более логичный поток и улучшает читаемость кода.

  • 0
    Это именно то, что я искал. Я знал, что в том, как я это делал, было что-то в корне не так. Спасибо
1

Первое, if(changeInfo.changeUsername === true) должно быть, if(changeInfo.changeEmail === true) следуя вашей логике.

  • 0
    Вы правы. Спасибо

Ещё вопросы

Сообщество Overcoder
Наверх
Меню