Как предотвратить повторяющиеся элементы в mongoDB при обновлении элемента - PullRequest
1 голос
/ 27 мая 2019

Я создаю многопользовательский словарь, куда несколько пользователей могут добавлять слова.Я не хочу, чтобы одно и то же слово могло повторяться.Мне удалось предотвратить повторение при добавлении слова, но я боролся с функциональностью, чтобы предотвратить повторение при обновлении слова.Например, в базе данных есть слово «яблоко», давайте представим, что кто-то хотел обновить слово «применить» и случайно написал «яблоко», в таком случае обновленное слово «яблоко» не должно попадать в базу данных, посколькутам уже такое слово.Пожалуйста, помогите мне.

Words API

const express = require('express');
const router = express.Router();
const Word = require('../../models/Word');
const validateWordInput = require('../../validation/word');
const passport = require('passport');

// @route  GET api/words/test
// @desc   tests words route
// @access Public
router.get('/test', (req, res) => res.json({ msg: 'Words works' }));

// @route  POST api/words
// @desc   Add words to profile
// @access Private
router.post(
  '/',
  passport.authenticate('jwt', { session: false }),
  (req, res) => {
    const { errors, isValid } = validateWordInput(req.body);

    // Check validation
    if (!isValid) {
      // Return any errors
      return res.status(400).json(errors);
    }

    Word.find({}).then(word => {
      if (
        word.filter(
          wrd =>
            wrd.ugrWordCyr.toString().toLowerCase() ===
            req.body.ugrWordCyr.toLowerCase()
        ).length !== 0
      ) {
        return res
          .status(404)
          .json({ wordalreadyexists: 'Word already exists' });
      } else {
        const newWord = new Word({
          user: req.user.id,
          ugrWordCyr: req.body.ugrWordCyr,
          rusTranslation: req.body.rusTranslation,
          example: req.body.example,
          exampleTranslation: req.body.exampleTranslation,
          origin: req.body.origin,
          sphere: req.body.sphere,
          lexis: req.body.lexis,
          grammar: req.body.grammar,
          partOfSpeech: req.body.partOfSpeech,
          style: req.body.style
        });

        newWord.save().then(word => res.json(word));
      }
    });
  }
);

// @route  Put api/words/:id
// @desc   Update a word by id
// @access Private

router.put(
  '/:id',
  passport.authenticate('jwt', { session: false }),
  (req, res) => {
    const { errors, isValid } = validateWordInput(req.body);

    // Check validation
    if (!isValid) {
      // Return any errors
      return res.status(400).json(errors);
    }

    Profile.findOne({ user: req.user.id }).then(profile => {
      Word.findById(req.params.id)
        .then(word => {
          // Check for word owner
          if (word.user.toString() !== req.user.id) {
            return res
              .status(401)
              .json({ notauthorized: 'User not authorized' });
          }

          const wordID = req.params.id;
          const wordInput = req.body;

          // Update
          Word.findByIdAndUpdate(
            { _id: wordID },
            { $set: wordInput },
            { returnOriginal: false },
            (err, word) => {
              if (err) {
                console.log(err);
              }
            }
          ).then(word => {
            res.json(word);
          });
        })
        .catch(err => res.status(404).json({ nowordfound: 'No word found' }));
    });
  }
);

// @route  GET api/words
// @desc   Dislay all words
// @access Public
router.get('/', (req, res) => {
  Word.find()
    .sort({ date: -1 })
    .then(words => res.json(words))
    .catch(err => res.status(404).json({ nonwordsfound: 'No words found' }));
});

//@route  Get api/words/:id
//@desc   Get word by id
//@access Public
router.get('/:id', (req, res) => {
  Word.findById(req.params.id)
    .then(word => res.json(word))
    .catch(err =>
      res.status(404).json({ nonwordfound: 'No word found with that ID' })
    );
});

//@route  DELETE api/words/:id
//@desc   DELETE word
//@access Private

router.delete(
  '/:id',
  passport.authenticate('jwt', { session: false }),
  (req, res) => {
    Profile.findOne({ user: req.user.id }).then(profile => {
      Word.findById(req.params.id)
        .then(word => {
          // Check for post owner
          if (word.user.toString() !== req.user.id) {
            return res
              .status(401)
              .json({ notauthorized: 'User not authorized' });
          }

          // Delete
          word.remove().then(() => res.json({ success: true }));
        })
        .catch(err => res.status(404).json({ postnotfound: 'No post found' }));
    });
  }
);

module.exports = router;

Я использовал следующий код для предотвращения повторного дублирования при добавлении.

   if (
                word.filter(
                  wrd =>
                    wrd.ugrWordCyr.toString().toLowerCase() ===
                    req.body.ugrWordCyr.toLowerCase()
                ).length !== 0
              ) {
                return res
                  .status(404)
                  .json({ wordalreadyexists: 'Word already exists' });
              } else {
                const newWord = new Word({
                  user: req.user.id,
                  ugrWordCyr: req.body.ugrWordCyr,
                  rusTranslation: req.body.rusTranslation,
                  example: req.body.example,
                  exampleTranslation: req.body.exampleTranslation,
                  origin: req.body.origin,
                  sphere: req.body.sphere,
                  lexis: req.body.lexis,
                  grammar: req.body.grammar,
                  partOfSpeech: req.body.partOfSpeech,
                  style: req.body.style
                });

Какой код нужно написать, чтобы сделатьто же самое при обновлении?

1 Ответ

2 голосов
/ 27 мая 2019

Перед выполнением Word.findByIdAndUpdate() вы можете проверить, соответствует ли текст в req.body каким-либо существующим словам в вашей базе данных.

// @route  Put api/words/:id
// @desc   Update a word by id
// @access Private

router.put(
  '/:id',
  passport.authenticate('jwt', { session: false }),
  (req, res) => {
    const { errors, isValid } = validateWordInput(req.body);

    // Check validation
    if (!isValid) {
      // Return any errors
      return res.status(400).json(errors);
    }

    Profile.findOne({ user: req.user.id }).then(profile => {
      Word.findById(req.params.id)
        .then(word => {
          // Check for word owner
          if (word.user.toString() !== req.user.id) {
            return res
              .status(401)
              .json({ notauthorized: 'User not authorized' });
          }

          const wordID = req.params.id;
          const wordInput = req.body;

         //find all words
          Word.find()
              .then((allWords) => {
                  //create an array of strings using each word ("apple", "apricot", ...etc)
                  const wordStrings = allWords.map((word) => word.ugrWordCyr) //not sure if thats the property that has the word-spelling

                  //check if user input already exists in all words
                  if(wordStrings.includes(req.body.ugrWordCyr)){
                       return res.status(400).json({ error : "word already exists" })
                  }

                  // Update
                  Word.findByIdAndUpdate(
                      { _id: wordID },
                      { $set: wordInput },
                      { returnOriginal: false },
                      (err, word) => {
                          if (err) {
                             console.log(err);
                          }
                      }).then(word => {
                           res.json(word);
                      });

               })
               .catch((errors) => {
                   return res.status(400).json({ errors: "could not find any words" })
               })

        })
        .catch(err => res.status(404).json({ nowordfound: 'No word found' }));
    });
  }
);

Кроме того, вы также можете обновить модель Word и использовать свойство unique при настройке схемы mongoose. Я представляю, что ваша схема выглядит примерно так:

const mongoose = require("mongoose")

    const wordSchema = new mongoose.Schema({
      user: {
        type: mongoose.Schema.Types.ObjectId,
        ref: "User"
      },
      ugrWordCyr: { type: String, unique: true}, <-- set unique to true
      rusTranslation: { type: String },
      example: { type: String },
      exampleTranslation: { type: String },
      origin: { type: String },
      sphere: { type: String },
      lexis: { type: String },
      grammar: { type: String },
      partOfSpeech: { type: String },
      style: { type: String }
    })

const Word = mongoose.model("Word", userSchema)

module.exports = Word

Теперь, когда вы используете findByIdAndUpdate(), оно не будет завершено, если вы не передадите новую / уникальную строку в ugrWordCyr или что-то, что вы используете в качестве явного слова.

      Word.findByIdAndUpdate(
        { _id: wordID },
        { $set: wordInput },
        { returnOriginal: false },
        (err, word) => {
          if (err) {
            console.log(err);
          }
        }
        ).then(word => {
             res.json(word);
          });
         .catch(err => {
             return res.status(400).json({ error: "could not update word" })
          })
       })
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...