【问题标题】:Mongoose Unique index not working!猫鼬唯一索引不起作用!
【发布时间】:2011-07-28 23:33:39
【问题描述】:

我试图让 MongoDB 根据其索引检测重复值。我认为这在 MongoDB 中是可能的,但是通过 Mongoose 包装器,事情似乎被破坏了。所以对于这样的事情:

User = new Schema ({
  email: {type: String, index: {unique: true, dropDups: true}}
})

我可以用同一封电子邮件保存 2 个用户。该死。

这里已经表达了同样的问题:https://github.com/LearnBoost/mongoose/issues/56,但该线程已经过时并且无处可去。

现在,我手动调用数据库来查找用户。该电话并不昂贵,因为“电子邮件”已编入索引。不过还是让它原生处理就好了。

有没有人可以解决这个问题?

【问题讨论】:

  • 坏消息,mongod v2.4.3,mongoose v3.6.20还是有问题
  • Unique 似乎可以在我的一台主机上运行,​​但无法在不同主机上使用完全相同的节点/猫鼬代码强制执行唯一性。正常工作的主机运行单个 mongod 3.4.10,不运行的主机使用 mongod 3.2.17 运行副本集。在两台主机上,我从头开始创建一个集合,因此现有的 dup 不是问题。我已经尝试了此页面上的大多数解决方案,其中一个有效的是来自@Isaac Pak 的 mongoose-unique-validator。
  • 如果您在现有模型中添加新的唯一字段,请查看此帖子-stackoverflow.com/questions/24430220/…

标签: mongodb node.js mongoose


【解决方案1】:

哎呀!你只需要重启 mongo。

【讨论】:

  • 我遇到了同样的问题,但我不知道如何在 OSX 上重新启动 mongo。当我终止该进程时,它会自动再次生成,并且唯一索引仍然无法正常工作......有什么想法吗?
  • “哎呀,你只需要重启 mongo”是什么意思?!你是说不关闭数据库就不可能添加索引?
  • 这不是真的。添加索引不需要重启 mongo。
  • 对于独特的东西..我不得不重新启动 mongo.. 它工作.. 谢谢!
  • 我尝试重新启动。还重新索引。不得不删除数据库来解决这个问题。猜测问题是在添加索引之前已经存在重复项,所以在生产数据库中我需要删除重复项然后重新启动?
【解决方案2】:

哎呀!你只需要重启 mongo。

并且也重新索引,使用:

mongo <db-name>
> db.<collection-name>.reIndex()

在测试中,由于我没有重要数据,你也可以这样做:

mongo <db-name>
> db.dropDatabase()

【讨论】:

  • db.dropDatabase() 擦除你的数据库!
【解决方案3】:

如果您在 Mongo 中留下了一些重复项,也会发生这种情况。当您的应用程序启动时,Mongoose 将尝试在 Mongo 中创建它们。

为了防止这种情况,你可以这样处理这个错误:

yourModel.on('index', function(err) {
  if (err?) {
    console.error(err)
  }
);

【讨论】:

    【解决方案4】:

    好的,我可以通过在字段上添加索引并设置唯一属性来从 mongoshell 解决这个问题:

    db.<collectionName>.ensureIndex({fieldName: 1}, {unique: true});
    

    Shell 应该这样响应:

    {
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
    }
    

    现在从 mongoshell 快速测试:

    var doc = {fieldName: 'abc'};
    db.<collectionName>.insert(doc)
    

    应该给出: WriteResult({ "nInserted" : 1 })

    但是当再次重复时:

    db.<collectionName>.insert(doc)
    

    将给予:

    WriteResult({
        "nInserted" : 0,
        "writeError" : {
            "code" : 11000,
            "errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: fuelConsumption.users.$email_1  dup key: { : \"martyna@martycud.com\" }"
        }
    })
    

    【讨论】:

      【解决方案5】:

      您也可以通过删除索引来解决此问题;

      假设您要从集合 users 和字段 username 中删除唯一索引,请输入:

      db.users.dropIndex('username_1');

      【讨论】:

        【解决方案6】:

        根据文档:https://docs.mongodb.com/v2.6/tutorial/modify-an-index/

        要修改现有索引,您需要删除并重新创建索引。

        不要重启 MONGO !

        1 - 删除集合

        db.users.drop()
        

        2 - 重新索引表

        db.users.ensureIndex({email: 1, type: 1}, {unique: true})
        

        【讨论】:

        • 它说删除索引而不是集合
        【解决方案7】:

        我遇到了同样的问题:在已经将用户添加到数据库之后,我将 email 字段的唯一约束添加到了我们的 UserSchema,并且仍然能够通过欺骗电子邮件保存用户。我通过执行以下操作解决了这个问题:

        1) 从用户集合中删除所有文档。

        2) 在 mongo shell 中,执行命令: db.users.createIndex({email: 1}, {unique: true})

        关于第 1 步,请注意来自 Mongo 的文档:

        如果集合已包含违反索引唯一约束的数据,则 MongoDB 无法在指定索引字段上创建唯一索引。

        https://docs.mongodb.com/manual/core/index-unique/

        【讨论】:

        • 如何删除某个索引?
        【解决方案8】:

        mongoose-unique-validator

        如何使用这个插件:

        1) npm install --save mongoose-unique-validator

        2) 在您的架构中遵循本指南:

        // declare this at the top
        var mongoose = require('mongoose');
        var uniqueValidator = require('mongoose-unique-validator');
        
        // exampleSchema = mongoose.Schema({}) etc...
        
        exampleSchema.plugin(uniqueValidator);
        
        // module.exports = mongoose.model(...) etc....
        

        3) 猫鼬方法

        当使用像findOneAndUpdate 这样的方法时,你需要传递这个配置对象:

        { runValidators: true, context: 'query' }

        ie. User.findOneAndUpdate(
              { email: 'old-email@example.com' },
              { email: 'new-email@example.com' },
              { runValidators: true, context: 'query' },
              function(err) {
                // ...
            }
        

        4) 附加选项

        1. 不区分大小写

          在您的架构中使用 uniqueCaseInsensitive 选项

          ie. email: { type: String, index: true, unique: true, required: true, uniqueCaseInsensitive: true }

        2. 自定义错误消息

          ie. exampleSchema.plugin(uniqueValidator, { message: 'Error, expected {PATH} to be unique.' });

        现在您可以在架构中添加/删除唯一属性,而无需担心重新启动 mongo、删除数据库或创建索引。

        注意事项(来自文档):

        因为我们依赖异步操作来验证一个文档是否存在于数据库中,所以有可能两个查询同时执行,都取回0,然后都插入到MongoDB中。

        除了自动锁定集合或强制单个连接之外,没有真正的解决方案。

        对于我们的大多数用户来说,这不是问题,但需要注意的边缘情况。

        【讨论】:

          【解决方案9】:

          如果表/集合为空,则为该字段创建唯一索引:

          db.<collection_name>.createIndex({'field':1}, {unique: true})
          

          如果表/集合不为空,则删除集合并创建索引:

          db.<collection_name>.drop()
          db.<collection_name>.createIndex({'field':1}, {unique: true})
          

          现在重启 mongoDB。

          【讨论】:

            【解决方案10】:

            最新答案:完全不需要重启mongodb, 如果 colleciton 已经有同名索引,mongoose 将不会重新创建 你的索引再次,所以,首先删除 colleciton 的现有索引, 现在,当你运行猫鼬时,它会创建新的索引, 以上过程解决了我的问题。

            【讨论】:

              【解决方案11】:

              Mongoose 在从应用程序级别强制执行唯一索引时有点松散;因此,最好使用 mongo cli 从数据库本身强制执行您的唯一索引,或者通过在 UserSchema 之后编写以下代码行来明确告诉 mongoose 您对unique 索引很认真:

              UserSchema.index({ username: 1, email: 1 }, { unique: true});

              这将在您的 UserSchema 中的 usernameemail 字段上强制执行唯一索引。干杯。

              【讨论】:

              • 聚会有点晚了,但是“在执行唯一索引时有点松散”的 ORM 有什么好处
              • 贬低没有任何帮助的cmets有什么好处。此解决方案可靠且可用于生产。
              【解决方案12】:

              如果您在这样的连接方法中使用选项autoIndex: false

              mongoose.connect(CONNECTION_STRING, { autoIndex: false });

              尝试删除它。如果这不起作用,请尝试 restarting mongodb 按照此线程中的许多建议。

              【讨论】:

                【解决方案13】:

                我做过这样的事情:

                const mongoose = require('mongoose');
                const Schema = mongoose.Schema;
                
                const FooSchema = new Schema({
                   name: { type: String, required: true, index: true, unique: true }
                });
                
                const Foo = mongoose.model('Foo', FooSchema);
                
                Foo.createIndexes();
                
                module.exports = Foo
                

                我添加了Foo.createIndexes() 行 b.c.运行代码时,我收到以下弃用警告:

                (node:21553) DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes instead.
                

                我不确定 Foo.createIndexes() 是否是异步的,但 AFAIK 的东西似乎工作正常

                【讨论】:

                • 解决问题而不是围绕问题的问题的唯一答案。
                • 这个答案对我有帮助。我所缺少的只是 index: true 用于创建我的唯一索引。
                【解决方案14】:

                检查架构中的 autoIndex 是否为真,当您使用 mongoose.connect 选项时,它可能设置为假(默认为真)

                【讨论】:

                  【解决方案15】:

                  您可以将架构定义为

                  User = new Schema ({
                    email: {
                        type: String,
                        unique: true
                    }
                  })
                  

                  但是当已经有一个文档并且之后你已经更改了用户的架构时,这可能不起作用。如果您不想删除该集合,您可以为此用户集合创建电子邮件索引。使用此命令,您可以在电子邮件上创建索引。

                  db.User.createIndex({email:1},{unique: true})
                  

                  或者您可以直接删除集合并再次添加用户。
                  对于删除集合,您可以输入:

                  db.User.drop()
                  

                  【讨论】:

                    【解决方案16】:

                    我曾经遇到过同样的问题并进行了大量搜索,我的解决方案是 createIndexes() 函数。

                    希望对您有所帮助。

                    所以代码会是这样的。

                    User = new Schema ({
                       email: {type: String, unique: true}
                    });
                    User.createIndexes();
                    

                    【讨论】:

                      【解决方案17】:

                      当我遇到这个问题时,我尝试删除数据库,多次重新启动服务器(nodemon),但所有技巧都没有奏效。我通过 Robo 3T 找到了以下解决方法:

                      1. 在 Robo 3T 中,双击数据库打开集合
                      2. 打开集合以显示相关集合。首先确保您的收藏为空
                      3. 右键单击索引文件夹。默认情况下,您将看到_id_ 作为默认值。现在,选择添加索引
                      4. 为电子邮件字段选择一个名称,例如email
                      5. 以 JSON 格式提供密钥。例如

                        {
                           "email": 1
                        }
                        
                      6. 点击唯一复选框

                      7. 保存

                      这将确保没有重复的电子邮件保存在 MongoDB 中。

                      【讨论】:

                      • object { "email": 1 } 这里的1是什么意思?
                      【解决方案18】:

                      确保您的集合没有多余的字段,您刚刚放置了唯一索引。

                      然后只需重新启动您的应用程序(猫鼬)。 它只是默默地添加索引失败。

                      【讨论】:

                        【解决方案19】:

                        在以下任一情况下,Mongoose 将默默地无法添加唯一索引:

                        1. 集合已有同名索引
                        2. 集合已包含带有索引字段重复的文档

                        在第一种情况下,使用db.collection.getIndexes() 列出索引,并使用db.collection.dropIndex("index_name") 删除旧索引。当您重新启动 Mongoose 应用程序时,它应该会正确添加新索引。

                        在第二种情况下,您需要在重新启动 Mongoose 应用程序之前删除重复项。

                        【讨论】:

                          【解决方案20】:

                          从集合中删除所有文档:

                          db.users.remove({})
                          

                          正如其他人提到的,重新启动对我有用

                          【讨论】:

                            【解决方案21】:

                            如果您的 MongoDB 正在作为服务工作(找到此问题的简单方法是,如果您不需要通过终端启动 mongod.exe 文件就不需要连接到数据库),那么在进行更改后,您可能需要重新启动服务和/或完全删除您的数据库。

                            这很奇怪,因为对于某些用户来说,只删除一个集合就可以了。其中一些只需要删除数据库。但那些对我不起作用。我删除了数据库,然后重新启动了 MongoDB Server 服务。

                            要重新启动服务,在 Windows 搜索栏搜索 Services,然后找到 MongoDB 服务,双击打开,然后停止并再次启动该服务。

                            如果其他方法不适合你,我相信这会成功。

                            【讨论】:

                              【解决方案22】:

                              就我而言,猫鼬已经过时了。我通过在 CMD 上运行 npm outdated 来检查它。 并更新了“猫鼬”。

                              请告诉您这是否也适用于您。

                              【讨论】:

                              • 你用的是什么版本?
                              【解决方案23】:

                              当您将数据库与应用程序连接时,添加此选项:“audoIndex: true” 例如在我的代码中我这样做了:

                              const options = {
                              // your options go here
                              ...
                              // this code is the solution
                              audoIndex: true
                              }
                              mongoose.connect(DB_URI, options);
                              

                              我还删除了我遇到问题的集合并重新创建它以确保它能够正常工作。 我在以下位置找到了这个解决方案:https://dev.to/emmysteven/solved-mongoose-unique-index-not-working-45d5 我也尝试了“重启 MongoDB”之类的解决方案,但对我不起作用。

                              【讨论】:

                                【解决方案24】:

                                解决问题的步骤:

                                1 .在属性中添加unique: true

                                let schema = new mongoose.Schema(
                                    {
                                        name: {
                                            type: String,
                                            unique: true,
                                            required: [true, "name required."],
                                        }
                                    }
                                );
                                
                                module.exports = mongoose.model("role", schema);
                                

                                2 。删除集合 - 例如role(最后一行)

                                • 这是一种简单的修复方法 - 如果您已经有重复的值。
                                • 您还可以删除集合中的所有记录,以便唯一列存在重复值(以上name

                                3 .重新启动使用 mongoose 库的 Node.js 服务器。


                                这里的其他一些答案怎么不正确?

                                • autoIndex 选项设置为 true

                                  • 不需要,默认为true
                                • 重启数据库

                                  • 不需要,只需要重启Node.js服务器

                                • 按照以上3个步骤in sequence
                                  • 如果您错过了什么,请重复 2 次​​li>

                                【讨论】:

                                  【解决方案25】:

                                  在我的例子中,我们需要定义 schema.index 来创建我们的索引。 请查看 Mongoose 文档索引https://mongoosejs.com/docs/guide.html#indexes

                                  • 注意,对架构进行更改后,记得重启服务器进行检查。

                                  现在看看下面的代码进行测试:

                                  const schemaUser = new mongoose.Schema(
                                    {
                                      username: {
                                        type: String,
                                        required: true,
                                        index: true,
                                        unique: true,
                                        dropDups: true,
                                      },
                                      hash: String,
                                      created: {
                                        type: Date,
                                        default: Date.now,
                                      },
                                    },
                                    {
                                      autoCreate: true, // auto create collection
                                      autoIndex: true, // auto create indexes
                                    }
                                  )
                                  // define indexes to be create
                                  schemaUser.index({ username: 1 })
                                  
                                  const User = mongoose.model('Users', schemaUser)
                                  const newUser = new Users({ username: 'wintzer' })
                                  newUser.save(function (err) {
                                    if (err) console.log(err)
                                  })
                                  

                                  【讨论】:

                                    【解决方案26】:

                                    重新启动和使用插件对我来说不起作用,而且在我们确信 mongo 可以自己完成的事情上使用插件有点矫枉过正。

                                    所以这里是修复。在您的连接函数中将其添加到选项对象(第二个参数)

                                    const options = {
                                      autoIndex: true, //this is the code I added that solved it all
                                    }
                                    mongoose.connect(process.env.MONGO_URI, options);
                                    

                                    【讨论】:

                                      【解决方案27】:

                                      一个老问题,但对于仍然遇到此问题的任何人,您可能没有正确应用索引:

                                      如果您在连接选项中将autoIndex 设置为false,则一种选择是将其设为true 或完全删除此属性,这会将其恢复为默认值true,但是,这不建议在生产环境中使用,因为这会影响性能,更好的方法是在模型上显式调用 createIndexes,这样可以正确创建架构中定义的索引。

                                      所以原始问题中示例的语法如下:

                                      const userSchema = new mongoose.Schema({
                                        email: { type: String, required: true, index: true, unique: true },
                                        // other fields
                                      });
                                      
                                      // methods, statics, hooks... etc
                                      
                                      const User = mongoose.model("User", userSchema);
                                      
                                      User.createIndexes();
                                      
                                      module.exports = User;
                                      
                                      

                                      【讨论】:

                                        【解决方案28】:

                                        在你的连接函数中不要忘记提及 useCreateIndex: true

                                        mongoose.connect(url, {
                                          useNewUrlParser: true,
                                          useCreateIndex: true,
                                          useFindAndModify: false,
                                          useUnifiedTopology: true,
                                        })
                                        

                                        【讨论】:

                                          猜你喜欢
                                          • 1970-01-01
                                          • 2014-07-29
                                          • 1970-01-01
                                          • 2015-03-11
                                          • 2014-11-12
                                          • 2018-08-29
                                          • 2016-08-05
                                          • 2012-06-25
                                          相关资源
                                          最近更新 更多