ChatGPT解决这个技术问题 Extra ChatGPT

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

以下是我在 user.js 模型中的 user 架构 -

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;

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

var user = require('./../models/user.js');

这就是我将它保存在数据库中的方式 -

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

错误 -

{"name":"MongoError","code":11000,"err":"insertDocument :: caused by :: 11000 E11000 duplicate key error index: mydb.users.$email_1  dup key: { : null }"} 

我检查了数据库集合并且不存在这样的重复条目,让我知道我做错了什么?

仅供参考 - req.body.emailreq.body.password 正在获取值。

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

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

有同样的错误!在开发过程中,我们禁用了自动索引并使用小写模式名称/键。我们后来决定改用 TitleCase,但未能更新我们的索引名称(即:titleCase 而不是 TitleCase)。所以当我们启用索引时,我们得到了这个错误。花了一点时间才弄清楚。您需要确保所有名称/键在任何地方都准确命名。
我遇到了同样的错误,将猫鼬模型设置为 unique: false 没有任何影响。我意识到我必须先放下桌子,然后它才会起作用。你可以做类似 db.whateverthecollection.drop({}) 的事情。小心,它会删除集合。
_id: mongoose.Types.ObjectId 添加,因为需要唯一的 id
@Pere 我不相信这行得通,谢谢

C
Community

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

相关文档:

如果文档在唯一索引中没有索引字段的值,则索引将为此文档存储空值。由于唯一性约束,MongoDB 将只允许一个缺少索引字段的文档。如果有多个文档没有索引字段的值或缺少索引字段,则索引构建将失败并出现重复键错误。您可以将唯一约束与稀疏索引结合起来,以从唯一索引中过滤这些空值并避免错误。

unique indexes

稀疏索引仅包含具有索引字段的文档的条目,即使索引字段包含空值。

换句话说,稀疏索引适用于所有具有 null 值的多个文档。

sparse indexes

来自评论:

您的错误表明该键名为 mydb.users.$email_1,这让我怀疑您在 users.emailusers.local.email 上都有索引(前者目前已旧且未使用)。从 Mongoose 模型中删除字段不会影响数据库。如果是这种情况,请使用 mydb.users.getIndexes() 检查并使用 mydb.users.dropIndex(<name>) 手动删除不需要的索引。


我刚刚删除了那个空文档,它起作用了:) +1 ..thx 寻求帮助
您的错误表明该键名为 mydb.users.$email_1,这让我怀疑您在 users.emailusers.local.email 上都有索引(前者目前已旧且未使用)。从 Mongoose 模型中删除字段不会影响数据库。如果是这种情况,请使用 mydb.users.getIndexes() 检查并使用 mydb.users.dropIndex(<name>) 手动删除不需要的索引。
或者,如果您要进行多项索引更改,请使用 db.users.dropIndexes()
当我在没有为新用户设置用户名的情况下使用 mongoose 插件 passport-local-mongoose 时,这对我来说是个问题。
这是一个问题或观点,甚至可能是意见,@titoih - 是 null 还是没有值是一个值,就像任何其他值一样,或者它是一个特例? “a@bc”和“a@bc”是一样的,“nothing”和“nothing”也一样吗?对于非稀疏索引,MongoDB 中的答案是“是”。其他数据库(如 MySQL)会说“不”。
R
Rick

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

从命令行

➜ mongo
use dbName;
db.dropDatabase();
exit

我认为这个解决方案非常激进,我认为 db.collection.dropIndexes() 就足够了,正如 cs_stackX 所说
@JorgeGarza 我有同样的问题。我刚刚放弃了收藏,之后一切都开始正常了。
我不小心用我的两个字段的唯一 ID 初始化了集合。后来,当我想添加具有相同 ID 的多个文档时,直到我删除集合并重新访问它,它才会让我这样做。
如果您是开发新手,这是一个尝试并找出解决方法的好机会……而不是在已经存储了千兆字节的用户数据后遇到这个问题
@JorgeGarza 的评论很有道理。重新启动服务器时,架构文件将再次重建删除的索引。而且,它奏效了。
D
Daggie Blanqx - Douglas Mwangi

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

我有一个应用程序。我希望人们使用他们的电子邮件、密码和电话号码进行注册。在我的 MongoDB 数据库中,我想根据他们的电话号码和电子邮件来唯一地识别人们 - 所以这意味着每个人的电话号码和电子邮件都必须是唯一的。

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

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

他们这样做。

我的数据库需要一个唯一的电子邮件地址字段 - 但我有很多人的电子邮件地址为“null”。所以我去我的代码并告诉我的数据库模式允许空/空的电子邮件地址字段,当那些承诺下周将他们的电子邮件添加到他们的个人资料的人时,我将用电子邮件唯一地址填写这些字段。

所以它现在对每个人来说都是双赢的(但你;-]):人们注册,我很高兴拥有他们的数据......我的数据库很高兴,因为它被很好地使用......但是你呢?我还没有给你创建架构的代码。

下面是代码: 注意:电子邮件中的 sparse 属性告诉我的数据库允许空值,这些空值稍后将被唯一值填充。

var userSchema = new mongoose.Schema({ local: { name: { type: String }, email : { type: String, require: true, index:true, unique:true,sparse:true}, 密码: { type: String ,要求:真},},脸书:{id:{类型:字符串},令牌:{类型:字符串},电子邮件:{类型:字符串},名称:{类型:字符串}}}); var User = mongoose.model('User',userSchema); module.exports = 用户;

我希望我已经很好地解释了它。快乐的 NodeJS 编码/黑客!


如果您需要 sparse 索引和 unique 验证,并且需要不需要的其他字段,则需要使用 partialFilterExpression 选项。查看此答案stackoverflow.com/a/34600171/728287
Y
Yegor

检查集合索引。

由于字段集合中的索引过时,我遇到了这个问题,这些字段应该由不同的新路径存储。

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


D
Daksh M.

好吧,基本上这个错误是说,您在特定字段上有一个唯一索引,例如:“email_address”,因此 mongodb 期望集合中每个文档的唯一电子邮件地址值。

因此,假设在您的架构中早些时候未定义唯一索引,然后您使用相同的电子邮件地址或没有电子邮件地址(空值)注册了 2 个用户。

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

你基本上有三个选择:

删除集合 db.users.drop();找到具有该值的文档并将其删除。假设该值为 null,您可以使用以下命令将其删除: db.users.remove({ email_address: null });删除唯一索引:db.users.dropIndex(indexName)

我希望这有帮助:)


b
bumsoverboard

https://i.stack.imgur.com/IERRr.png


感谢您提供此问题的图形解决方案!工作完美。
谢谢,它工作得很好。这是我找到的唯一解决方案
谢谢你这对我有用。我只是在我的情况下删除了电子邮件和电话的索引。它对我有用
t
tonisanchez.dev

编辑:此解决方案在 2022 年仍然有效,您无需放弃收藏或丢失任何数据。

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

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

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

这是为什么?在我的情况下很简单,它曾经只接受唯一值的架构上的字段,但我只是将其更改为接受重复值。 Mongodb creates indexes for fields with unique values 为了更快地检索数据,所以过去 mongo 为该字段创建了该索引,因此即使在架构上将“唯一”属性设置为“false”后,mongodb 仍在使用该索引,并对其进行处理因为它必须是独一无二的。

如何解决

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

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

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

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

https://i.stack.imgur.com/gvYVU.png

https://i.stack.imgur.com/jbHIv.png


m
mad Man

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


K
Kobe Luo

这是我的相关经验:

在“用户”模式中,我将“名称”设置为唯一键,然后运行一些执行,我认为这已经设置了数据库结构。

然后我将唯一键更改为“用户名”,并且在将数据保存到数据库时不再传递“名称”值。所以mongodb可能会自动将新记录的'name'值设置为null,即重复键。我尝试在“用户”架构中将“名称”键设置为非唯一键 {name: {unique: false, type: String}},以覆盖原始设置。但是,它没有用。

最后,我提出了自己的解决方案:

只需设置一个随机键值,当您保存数据记录时,该键值不太可能与“名称”键重复。简单数学方法 '' + Math.random() + Math.random() 生成一个随机字符串。


我认为这不是一个有效的解决方案,您只是掩盖了问题。
丑陋但务实
S
Sandip Subedi

我遇到过同样的问题。尝试调试不同的方式无法弄清楚。我尝试删除该集合,之后效果很好。虽然如果您的收藏有很多文档,这不是一个好的解决方案。但是,如果您处于开发的早期状态,请尝试删除该集合。

db.users.drop();

A
Alamin

我已经通过这种方式解决了我的问题。

只需进入您的 mongoDB 帐户 -> Atlast 集合然后删除您的数据库列。或者去 mongoDB compass 然后删除你的数据库,

当您在数据库中保存一些空值时,有时会发生这种情况。


仅供参考 - 你不需要删除分贝。您可以转到 Compass,然后转到集合,然后转到索引选项卡,您就可以删除该索引
I
Ignatius Andrew

这是因为已经有一个与配置同名的集合..只需通过 mongo shell 从您的 mongodb 中删除该集合,然后重试。

db.collectionName.remove()

现在运行你的应用程序它应该可以工作


E
Embedded_Mugs

我有一个类似的问题,我意识到默认情况下 mongo 每个集合只支持一个模式。要么将新架构存储在不同的集合中,要么删除当前集合中架构不兼容的现有文档。或者找到一种方法让每个集合拥有多个模式。


h
halfer

当我在 config/models.js 中有以下配置时,我遇到了同样的问题

module.exports.models = {
  connection: 'mongodb',
  migrate: 'alter'
}

将迁移从“更改”更改为“安全”为我修复了它。

module.exports.models = {
  connection: 'mongodb',
  migrate: 'safe'
}

C
Christian Hartmann

在第一次在保存时建立一些索引后从模式中删除属性后出现同样的问题。从架构中删除属性会导致不存在的属性为空值,该属性仍然具有索引。删除索引或从头开始一个新的集合在这里有帮助。

注意:在这种情况下,错误消息将引导您。它有一条不再存在的路径。我的情况是旧路径是 ...$uuid_1 (这是一个索引!),但新路径是 ....*priv.uuid_1


I
Inamur Rahman

我也遇到过这个问题,我解决了。此错误表明此处已存在电子邮件。因此,您只需从 Model for email 属性中删除此行。

unique: true

即使它不起作用,这也可能是可能的。所以只需要从 MongoDB 中删除集合并重新启动服务器。


A
Abu Sayem Md Habibullah

这不是一个大问题,但是像我这样的初学者级别的开发人员,我们会考虑这是什么类型的错误,最后我们浪费了大量时间来解决它。

实际上,如果您删除数据库并再次创建数据库并尝试创建集合之后,它将正常工作。

➜ mongo
use dbName;
db.dropDatabase();
exit

D
Dharman

删除您的数据库,然后它将起作用。

您可以执行以下步骤来删除数据库

第一步:进入mongodb安装目录,默认目录为“C:\Program Files\MongoDB\Server\4.2\bin”

第2步:直接启动mongod.exe或使用命令提示符并最小化它。

第 3 步:直接启动 mongo.exe 或使用命令提示符并运行以下命令

i) 使用 yourDatabaseName(如果您不记得数据库名称,请使用 show databases)

ii) db.dropDatabase()

这将删除您的数据库。现在您可以插入数据,它不会显示错误,它会自动添加数据库和集合。


R
Rahul P

当我尝试修改使用 mangoose 定义的架构时,我遇到了同样的问题。我认为问题是由于在创建集合时完成了一些基本过程,例如描述对用户隐藏的索引(至少在我的情况下)。所以我找到的最佳解决方案是删除整个集合并重新开始。


J
John Conde

如果您处于开发的早期阶段:消除集合。否则:将此添加到每个给您错误的属性(注意:我的英语不好,但我尝试解释一下)

index:true,
unique:true,
sparse:true

t
tariel

就我而言,我只是在发现具有 req.email 的用户已经存在后忘记返回 res.status(400)


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅