Mongodb mongoose中的E11000重复键错误索引

Tri*_*der 197 mongoose mongodb node.js

以下是模型user中的user.js模式 -

var userSchema = new mongoose.Schema({
    local: {
        name: { type: String },
        email : { type: String, require: true, unique: true },
        password: { type: String, require:true },
    },
    facebook: {
        id           : { type: String },
        token        : { type: String },
        email        : { type: String },
        name         : { type: String }
    }
});

var User = mongoose.model('User',userSchema);

module.exports = User;
Run Code Online (Sandbox Code Playgroud)

这就是我在我的控制器中使用它的方式 -

var user = require('./../models/user.js');
Run Code Online (Sandbox Code Playgroud)

这就是我在db中保存它的方法 -

user({'local.email' : req.body.email, 'local.password' : req.body.password}).save(function(err, result){
    if(err)
        res.send(err);
    else {
        console.log(result);
        req.session.user = result;
        res.send({"code":200,"message":"Record inserted successfully"});
    }
});
Run Code Online (Sandbox Code Playgroud)

错误 -

{"name":"MongoError","code":11000,"err":"insertDocument :: caused by :: 11000 E11000 duplicate key error index: mydb.users.$email_1  dup key: { : null }"} 
Run Code Online (Sandbox Code Playgroud)

我检查了db集合,没有这样的重复条目存在,让我知道我做错了什么?

仅供参考 - req.body.email并且req.body.password正在获取价值.

我也检查了这篇文章,但没有帮助STACK LINK

如果我完全删除然后它插入文档,否则它会抛出错误"重复"错误,即使我在local.email中有一个条目

Rik*_*kus 202

错误消息说已经有一个记录null作为电子邮件.换句话说,您已经拥有一个没有电子邮件地址的用户.

相关文件:

如果文档没有唯一索引中索引字段的值,则索引将为此文档存储空值.由于唯一约束,MongoDB只允许一个缺少索引字段的文档.如果有多个文档没有索引字段的值或缺少索引字段,则索引构建将失败并出现重复键错误.

您可以将唯一约束与稀疏索引结合使用,以从唯一索引中过滤这些空值并避免错误.

独特的索引

稀疏索引仅包含具有索引字段的文档的条目,即使索引字段包含空值也是如此.

换句话说,稀疏索引可以使多个文档都具有null值.

稀疏索引


来自评论:

你的错误说密钥被命名mydb.users.$email_1,这让我怀疑你有两个索引users.emailusers.local.email(前者是旧的和目前未使用的).从Mongoose模型中删除字段不会影响数据库.检查mydb.users.getIndexes()是否是这种情况,并手动删除不需要的索引mydb.users.dropIndex(<name>).

  • 你的错误说密钥被命名为`mydb.users.$ email_1`,这让我怀疑你有'users.email`和`users.local.email`的索引(前者现在已经过时且未被使用).从Mongoose模型中删除字段不会影响数据库.如果是这种情况,请检查`mydb.users.getIndexes()`并使用`mydb.users.dropIndex(<name>)`手动删除不需要的索引. (66认同)
  • 或者如果要进行多个索引更改,请使用`db.users.dropIndexes()` (16认同)
  • 当我使用猫鼬插件passport-local-mongoose而没有为新用户设置用户名时,这对我来说是一个问题。 (2认同)

Ric*_*ick 53

如果您仍在开发环境中,我会删除整个数据库并重新开始使用新模式.

从命令行

? mongo
use dbName;
db.dropDatabase();
exit
Run Code Online (Sandbox Code Playgroud)

  • 我认为这个解决方案是非常积极的,我认为足够用`db.collection.dropIndexes()`作为cs_stackX说 (38认同)
  • @JorgeGarza 我有同样的问题。我刚刚放弃了收藏,之后一切都开始正常工作。 (3认同)
  • 如果您是开发新手,这是一个很好的机会进行试验并找出解决此问题的方法...而不是在已经存储了千兆字节的用户数据后遇到此问题 (2认同)

Hum*_*ber 23

编辑:此解决方案在 2023 年仍然有效,您不需要删除您的收藏或丢失任何数据。

以下是我在 2020 年 9 月解决相同问题的方法。从 mongodb 图集(云和桌面)有一种超快速且简单的方法。以前恐怕没那么容易吧?这就是为什么我觉得我应该在2020年写这个答案。

首先,我在上面读到了一些更改猫鼬模式上“唯一”字段的建议。如果您出现此错误,我假设您已经更改了架构,但尽管如此,您还是得到了 500 作为响应,并注意这一点:指定重复的 KEY!。如果问题是由模式配置引起的,并且假设您已经配置了一个不错的中间件来记录 mongo 错误,则响应将是 400。

为什么会发生这种情况(至少是主要原因)

这是为什么?就我而言,很简单,架构上的该字段过去只接受唯一值,但我只是将其更改为接受重复值。MongoDB为具有唯一值的字段创建索引,以便更快地检索数据,因此过去 mongo 为该字段创建了该索引,因此即使在模式上将“unique”属性设置为“false”之后,mongodb 仍在使用该索引,并认为它必须是唯一的。

如何解决

删除该索引。您可以在 2 秒内从 Mongo Atlas 完成此操作,或者在 mongo shell 上将其作为命令执行。为了简单起见,我将为不使用 mongo shell 的用户展示第一个。

去你的收藏吧。默认情况下,您位于“查找”选项卡上。只需选择右侧的下一个:“索引”。您将看到同一字段仍然有索引给您带来麻烦。只需单击“删除索引”按钮即可。完毕。

所以不要每次发生这种情况时都删除数据库

我相信这是一个比仅仅删除整个数据库甚至集合更好的选择。基本上是因为这就是它在删除整个集合后起作用的原因。因为如果您的第一个条目使用带有“unique: false”的新架构,mongo 不会为该字段设置索引。

服务器响应

云图


Yeg*_*gor 16

检查收集索引.

我有这个问题,因为字段集合中的过时索引应该由不同的新路径存储.

当您将字段指定为唯一时,Mongoose会添加索引.


Dak*_*ani 16

基本上这个错误就是说,你在特定字段上有一个唯一的索引,例如:"email_address",所以mongodb期望集合中每个文档的唯一电子邮件地址值.

因此,我们可以说,在您的架构中,未定义唯一索引,然后您使用相同的电子邮件地址或没有电子邮件地址(空值)注册了2个用户.

后来,你看到有一个错误.因此,您尝试通过向架构添加唯一索引来更正它.但是您的集合已经有重复项,因此错误消息表明您无法再次插入重复值.

你基本上有三个选择:

  1. 删除集合

    db.users.drop();

  2. 找到具有该值的文档并将其删除.假设值为null,您可以使用以下命令将其删除:

    db.users.remove({ email_address: null });

  3. 删除唯一索引:

    db.users.dropIndex(indexName)

我希望这有帮助:)


Dag*_*nqx 14

我想解释这个问题的答案/解决方案就像我向一个5岁的孩子解释一样,所以每个人都能理解.

我有一个app.I希望人们注册他们的电子邮件,密码和电话号码.在我的MongoDB数据库中,我想根据他们的电话号码和电子邮件识别出唯一的人 - 这意味着电话号码和电子邮件必须对每个人都是唯一的.

但是,有一个问题:我已经意识到每个人都有一个电话号码,但不是每个人都有一个电子邮件地址.

那些没有电子邮件地址的人已经答应我,他们将在下周收到一个电子邮件地址.但我还是希望他们注册 - 所以我告诉他们继续注册他们的电子邮件,因为他们将电子邮件输入字段留空.

他们这样做了.

我的数据库需要一个唯一的电子邮件地址字段 - 但我有很多人使用'null'作为他们的电子邮件地址.所以我转到我的代码并告诉我的数据库架构允许空/空电子邮件地址字段,当我们承诺将在下周将其电子邮件添加到他们的个人资料中时,我将在后面填写电子邮件唯一地址.

所以它现在对每个人来说都是双赢的(但是你; - )):人们注册,我很高兴得到他们的数据......我的数据库很高兴,因为它被很好地使用了...但你怎么样?我还没有给你制作模式的代码.

下面是代码: 注意:电子邮件中的稀疏属性告诉我的数据库允许空值,以后将使用唯一值填充.

var userSchema = new mongoose.Schema({
  local: {
    name: { type: String },
    email : { type: String, require: true, index:true, unique:true,sparse:true},
    password: { type: String, require:true },
  },
  facebook: {
    id           : { type: String },
    token        : { type: String },
    email        : { type: String },
    name         : { type: String }
  }
});

var User = mongoose.model('User',userSchema);

module.exports = User;
Run Code Online (Sandbox Code Playgroud)

我希望我能很好地解释它.快乐的NodeJS编码/黑客!


bum*_*ard 12

在这种情况下,登录 Mongo 找到您不再使用的索引(在 OP 的情况下为“电子邮件”)。然后选择删除索引 在此处输入图片说明

  • 感谢您提供该问题的图形解决方案!效果很好。 (4认同)

小智 7

我遇到了类似的问题,我只是清除特定字段的索引,然后它的工作对我来说. https://docs.mongodb.com/v3.2/reference/method/db.collection.dropIndexes/