解决 Mongoose 保存中 “Unique” 约束失败的问题

阅读时长 6 分钟读完

前言

Mongoose 是一个基于 Node.js 的 MongoDB 驱动程序,它为开发者提供了模式建模工具,同时支持中间件和其他常见的 ORM 功能,方便快速地在 Node.js 端建立和操作 MongoDB 数据库。但是,在使用 Mongoose 保存数据的过程中,如果遇到需要使用“唯一性约束(Unique)”的情况,有时候会遇到保存失败的问题。

本文将围绕“唯一性约束(Unique)”在 Mongoose 中保存的问题,详细讲解其中的原因,并提出多种解决方案,以期对广大前端开发者具有一定的学习和指导意义。

问题描述

在 Mongoose 中,如果给 Model 添加唯一性约束,意义是保证该字段值在整个数据库中是唯一的,避免重复的数据。例如,我们为 User Model 的 email 字段添加唯一约束:

-- -------------------- ---- -------
----- ---------- - --- --------
  ------ -
    ----- -------
    ------- -----
  --
  ----- -------
  ---- -------
---

----- --------- - ---------------------- ------------

那么在插入数据时,如果插入的数据中 email 字段已经在数据库中存在,则插入操作将会失败:

-- -------------------- ---- -------
----- ----- - --- -----------
    ------ -------------------
    ----- -----
    ---- --
---

------------------- ----- ----- -
    -- ----- -
        --------------------
    - ---- -
        --------------------
    -
---

但是,在实际应用过程中,有人会发现无论如何插入都会失败,并提示“E11000 duplicate key error collection”:

-- -------------------- ---- -------
----- ----- - --- -----------
    ------ -------------------
    ----- -----
    ---- --
---

----- ----- - --- -----------
    ------ -------------------
    ----- ------
    ---- --
---

------------------- ----- ----- -
    -- ----- -
        -------------------- -----
    - ---- -
        -------------------- ------
    -
---

------------------- ----- ----- -
    -- ----- -
        -------------------- -----
    - ---- -
        -------------------- ------
    -
---

这时候我们需要解决这个问题,让数据顺利的存入数据库。

问题原因

Mongoose 中常常出现“Unique”约束失败的情况,是因为 MongoDB 的多个连接在进行保存操作时出现了竞争的情况,从而导致两个请求同时想要插入一条 email 字段值相同的数据,但实际只能有一个请求操作成功,另一个则失败。此时 Mongoose 就会报出上述的错误,提示要求在 email 字段上添加“唯一性约束”。

具体的原理是,MongoDB 使用了一个叫做“Write Concern” 的机制。在默认情况下,MongoDB 只保证一个操作被提交到副本集的主节点,并成功地进行了写入操作。因此,在多个连接并发操作时就会出现竞争问题。

解决方案

为了解决这个问题,我们需要考虑多个方面。以下是几种可行的方案:

1. 实现唯一性约束的错误处理

Mongoose 不支持结果集中的唯一键约束错误。不过,可以利用 MongoDB 向开发人员发送有关唯一键冲突的信息。

-- -------------------- ---- -------
------------------- ----- ----- -
    -- ---- -- -------- --- ------ -
        ----------------------- -------------
    - ---- -- ----- -
        -------------------- -----
    - ---- -
        -------------------- ------
    -
---

在上述代码中,我们直接访问错误代码 err,如果 code 值为 11000,就表示唯一性约束冲突,可以通过查询错误消息 err.message 获取更具体的错误信息。

2. 使用批量更新

Mongoose 可以利用 MongoDB 提供的批量更新功能来规避唯一性约束的错误。通过使用 $setOnInsert 和 upsert 选项来设置一个对象。

-- -------------------- ---- -------
------------------------ ------------- -
    ------------- -
      ------ ------------
      ----- -----------
      ---- ----------
    -
-- -------- ------ -------- ----- ------- -
    -- ----- -
        -------------------- -----
    - ---- -
        -------------------- --------
    -
---

在上述代码中,使用 mongoose 的model的 update 方法来更新数据库的记录,如果 email 字段已经存在,则更新相应的值,否则进行插入操作。

3. 降低竞争条件

可以降低竞争条件来解决“Unique”约束失败的情况。

-- -------------------- ---- -------
------------------- ------ ----------- -- ------------- ---- -
  ------- -
    -------------------
    -------
  -
  ------- -
    ----------------------- -----
    -------
  -
  ------------------------ ----- -
    -- ----- -
        -------------------- -----
    - ---- -
        -------------------- ------
    -
  --
--

在上述代码中,我们先查询数据库中是否已存在 email 值相同的数据,如果存在,则返回或更新。如果不存在,则再进行插入操作。

总结

通过本文的介绍,我们了解到了“唯一性约束(Unique)”在 Mongoose 中保存失败的各种情况。对于任何一种技术问题,都需要我们认真分析其原因,并且采用合适的解决方案,从而解决问题。遇到“唯一性约束(Unique)”约束失败的问题时,我们需要注意减少连接并发操作产生的竞争冲突;可以利用批量更新、错误信息提示等方式解决问题。我们希望本篇文章对广大前端开发者具有一定的学习和指导意义。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/651eac0e95b1f8cacd658cbf

纠错
反馈