【问题标题】:Avoid duplicates when saving new data with mongoose使用 mongoose 保存新数据时避免重复
【发布时间】:2020-05-18 12:44:32
【问题描述】:

我正在开发一个可以将目的地保存到我的 Mongo DB 的应用程序。在尝试保存数据库中已经存在的目标时,我想抛出一个自定义错误。 Mongoose 可以防止这种情况发生,但我想要清晰且用户友好的错误处理。

// post a new destination

router.post('/',
  (req, res) => {
    const newCity = new cityModel(
      {
        name: req.body.name,
        country: req.body.country
      }
    )
    newCity.save()
      .then(city => {
        res.send(city)
      })
      .catch(err => {
        res.status(500).send('Server error')
      })
  });

【问题讨论】:

    标签: javascript mongodb mongoose ecmascript-6 error-handling


    【解决方案1】:

    在保存新目的地之前,您可以检查是否有文档已经使用findOne 方法,如果存在,您可以返回自定义错误。

    router.post("/", async (req, res) => {
      const { name, country } = req.body;
    
      try {
        const existingDestination = await cityModel.findOne({name,country});
    
        if (existingDestination) {
          return res.status(400).send("Destionation already exists");
        }
    
        let newCity = new cityModel({ name, country });
    
        newCity = await newCity.save();
        res.send(city);
      } catch (err) {
        console.log(err);
        res.status(500).send("Server error");
      }
    });
    

    请注意,我猜想当存在相同的国家和名称时会发生重复。如果不是您想要的,您可以在 findOne 中更改查询。

    【讨论】:

    • 我不会就此争论或说不应该这样做,但一般来说,您不会故意将副本写入数据库,许多正确的机会可能很小,但是这样做你需要对所有进入数据库的唯一性进行两次数据库调用。唯一索引的目的不仅限于避免意外创建重复项,还用于减少应用程序进行的此类预检查。
    • @ZoltanSzokodi 你为什么改变主意?这个答案更干净。其他答案有我在该答案中评论过的问题。
    【解决方案2】:

    由于您已经创建了unique 索引,当您尝试写入重复时,结果将是:

    WriteResult({
       "nInserted" : 0,
       "writeError" : {
          "code" : 11000,
          "errmsg" : "E11000 duplicate key error index: test.collection.$a.b_1 dup key: { : null }"
       }
    })
    

    您的代码:

    常量文件:

    module.exports = {
        DUPLICATE_DESTINATION_MSG: 'Destionation values already exists',
        DUPLICATE_DESTINATION_CODE: 4000
    } 
    

    代码:

    //post a new destination
    const constants = require('path to constants File');
    router.post('/',
        (req, res) => {
            const newCity = new cityModel(
                {
                    name: req.body.name,
                    country: req.body.country
                }
            )
            try {
                let city = await newCity.save();
                res.send(city)
            } catch (error) {
                if (error.code == 11000) res.status(400).send(`Destination - ${req.body.name} with country ${req.body.country} already exists in system`);
                /* In case if your front end reads your error code &
                    it has it's own set of custom business relates messages then form a response object with code/message & send it. 
                if (error.code == 11000) {
                    let respObj = {
                        code: constants.DUPLICATE_DESTINATION_CODE,
                        message: constants.DUPLICATE_DESTINATION_MSG
                    }
                    res.status(400).send(respObj);
                } */
            }
            res.status(500).send('Server error');
        })
    

    【讨论】:

    • 如果还有其他唯一索引,那么这段代码会误导用户目的地已经存在。
    • @SuleymanSah :如果输入请求有其他具有唯一索引的字段,那么这可能是可能的,在这种情况下,您可以读取消息以获取 dup 键名称并仅在代码匹配到 11000 后对其进行匹配(对于不是所有其他错误),只有在输入具有多个唯一性的字段时,才会对负面情况进行更高级别的检查!
    • 这会让你的答案更加复杂。
    • @SuleymanSah :我不认为,我不会担心在不时执行的负面场景中编写代码,而不是对每个请求进行检查 - 如果您知道您的请求,则不需要和回应:-) !!!假设即使您进行了预检查,那么您也必须编写“if”块来检查所有字段,但如果您在错误情况下进行相同的检查,您可能只是通过一次检查传递错误消息......虽然它有效,我想知道它使哪些场景变得复杂?
    猜你喜欢
    • 2021-05-15
    • 2013-04-07
    • 2011-08-25
    • 2014-12-23
    • 2020-11-15
    • 1970-01-01
    • 1970-01-01
    • 2015-10-16
    • 2016-07-24
    相关资源
    最近更新 更多