更新项目时如何防止mongoDB中出现重复项目

时间:2019-05-27 06:39:18

标签: node.js reactjs mongodb redux

我正在创建一个多用户字典,几个用户可以在其中添加单词。我不希望同一词有重复的意思。添加单词时,我能够防止出现重复现象,但是在更新单词时却无法防止出现重复现象。例如,数据库中有一个单词“ apple”,让我们假设有人想要更新一个单词“ apply”并无意中写了“ apple”,在这种情况下,更新的单词“ apple”不应该进入数据库,因为那里已经有这样的词了。请帮我。

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 个答案:

答案 0 :(得分:2)

在执行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属性。我想您的架构看起来像这样:

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" })
          })
       })