MERN Stack: Как запретить пользователю регистрироваться (добавляться в массив) несколько раз? - PullRequest
0 голосов
/ 15 апреля 2020

Полу-новый разработчик, создающий проект с использованием стека MERN.

Приложение имеет две модели: одну для Users и одну для Tournaments. Модель турнира имеет атрибут participants, который является массивом.

Я написал Express внутренний маршрут, чтобы пользователь мог зарегистрироваться на Tournaments.participants []. Это выглядит так:

router.post('/:id', (req, res) => {
    Tournament.findById(req.params.id)
        .then(tournament => {
            tournament.participants.push(req.body);
            return tournament.save();
        })
        .then(savedTournament => res.json(savedTournament))
        .catch(err => res.json(err));
});

Однако пользователь может просто нажимать кнопку «Регистрация», и у меня будет куча дублирующих пользователей, поэтому я пытаюсь написать условие, которое отключит регистрацию, если пользователь уже участвует в Tournament.participants [].

Я попытался написать условное выражение внутри маршрута Express, используя Array.includes(req.body), но не смог его взломать. Выглядело что-то вроде

Tournament.findById(req.params.id)
        .then(tournament => {
            if (tournament.participants.includes(req.body) {
              return res.status(400).json({ msg: "This user already signed up for this tournament" });
            } else {
              tournament.participants.push(req.body);
              return tournament.save();
            }
        })
        .then(savedTournament => res.json(savedTournament))
        .catch(err => res.json(err));

Я также пробовал разные варианты, например if (tournament.participants.includes(!req.body)) затем pu sh (req.body) и т. Д. c.

И я также попробовал просто рендеринг другой кнопки, если participants.includes(user), но я считаю, что это должно быть сделано на бэкэнде в любом случае ... Я открыт для предложений.

Кто-нибудь может мне помочь?

Ответы [ 2 ]

1 голос
/ 15 апреля 2020

Как правило, вы не можете использовать встроенные операторы сравнения с объектами, includes включено:

const foo = { id: 1 };
const bar = [{ id: 1 }];
console.log(bar.includes(foo)); // outputs `false`

Вы должны использовать какой-то элемент id, чтобы проверить, существует ли он уже:

function isIdIncluded(arr, id) {
  return arr.some(x => x.id === id) 
}

const foo = { id: 1 };
const bar = [{ id: 1 }];
console.log(isIdIncluded(bar, 1)); // outputs `true`
0 голосов
/ 15 апреля 2020

Я предполагаю, что вы сохраняете _id пользователя в массиве participants, и ваша схема турнира похожа на эту:

const tournamentSchema = new mongoose.Schema({
  name: String,
  participants: Array,
});

Теперь, если вы отправляете запрос с этим телом:

{
    "user": "5e97255a342f395774f30162"  //the user id who wants to participate
}

Вы можете использовать этот код (я только что изменил req.body на req.body.user)

  Tournament.findById(req.params.id)
    .then((tournament) => {
      if (tournament.participants.includes(req.body.user)) {
        return res.status(400).json({ msg: "This user already signed up for this tournament" });
      } else {
        tournament.participants.push(req.body.user);
        return tournament.save();
      }
    })
    .then((savedTournament) => res.json(savedTournament))
    .catch((err) => res.status(500).json(err));

Теперь, когда пользователь впервые участвует в турнире, документ будет выглядеть так:

{
    "participants": [
        "5e97255a342f395774f30162"
    ],
    "_id": "5e97255a342f395774f30161",
    "name": "Chess Tournament"
}

И когда тот же пользователь пытается, ответ будет таким с кодом состояния 400.

{
    "msg": "This user already signed up for this tournament"
}

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

...