122

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

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

我可以使用相同的电子邮件保存 2 个用户。该死。

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

现在,我手动调用数据库来查找用户。该电话并不昂贵,因为“电子邮件”已编入索引。但是让它在本地处理仍然很好。

有人对此有解决方案吗?

4

28 回答 28

116

哎呀!你只需要重新启动 mongo。

于 2011-04-04T07:22:07.803 回答
43

哎呀!你只需要重新启动 mongo。

并重新索引,使用:

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

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

mongo <db-name>
> db.dropDatabase()
于 2012-10-29T12:37:37.457 回答
36

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

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

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

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

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

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

于 2016-10-13T16:56:58.453 回答
18

我做了这样的事情:

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()行 bc 在运行代码时收到以下弃用警告:

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

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

于 2018-09-18T22:05:53.003 回答
12

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

为防止这种情况,您可以通过以下方式处理此错误:

yourModel.on('index', function(err) {
  if (err?) {
    console.error(err)
  }
);
于 2014-01-04T15:41:07.273 回答
11

好的,我可以通过在字段上添加索引并设置唯一属性来从 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\" }"
    }
})
于 2014-12-10T21:42:21.080 回答
9

解决问题的步骤:

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

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

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

  • 按照以上3个步骤in sequence
    • 如果你错过了什么,做2次
于 2021-02-17T04:17:58.370 回答
7

根据文档: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})
于 2016-08-04T17:39:53.177 回答
6

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

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

这将对您的 UserSchema 中的username和字段强制执行唯一索引。email干杯。

于 2017-11-26T03:45:56.300 回答
5

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

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

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

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

于 2020-03-15T13:34:50.370 回答
3

猫鼬唯一验证器

如何使用这个插件:

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中。

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

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

于 2017-03-21T14:47:45.353 回答
3

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

于 2017-10-19T23:08:08.093 回答
1

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

假设您要从 collectionusers和 field中删除唯一索引username,请输入:

db.users.dropIndex('username_1');

于 2015-12-17T20:00:46.370 回答
1

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

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

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

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

现在重新启动 mongoDB。

于 2017-09-14T10:31:44.630 回答
1

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

于 2019-05-10T03:46:29.633 回答
1

我有一段时间遇到同样的问题并做了很多搜索,对我来说解决方案就是createIndexes()函数。

我希望这会有所帮助。

所以代码将是这样的。

User = new Schema ({
   email: {type: String, unique: true}
});
User.createIndexes();
于 2019-06-18T23:30:39.413 回答
1

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

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

const options = {
  autoIndex: true, //this is the code I added that solved it all
}
mongoose.connect(process.env.MONGO_URI, options);
于 2021-07-26T08:26:04.643 回答
0

如果您autoIndex: false在连接方法中使用该选项,如下所示:

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

尝试删除它。如果这不起作用,请尝试按照此线程中的建议重新启动 mongodb 。

于 2018-08-18T14:32:47.213 回答
0

您可以将架构定义为

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

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

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

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

db.User.drop()
于 2019-06-18T15:52:23.377 回答
0

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

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

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

  7. 节省

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

于 2019-07-08T08:10:39.567 回答
0

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

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

于 2020-02-12T08:14:32.403 回答
0

从集合中删除所有文档:

db.users.remove({})

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

于 2020-06-02T18:54:51.333 回答
0

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

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

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

如果其他方法对您不起作用,我相信这会起作用。

于 2020-08-20T02:08:21.810 回答
0

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

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

于 2020-08-25T10:02:42.497 回答
0

当您将数据库与应用程序连接时,添加此选项:“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”之类的解决方案,但对我不起作用。

于 2020-10-11T03:27:33.517 回答
0

在我的例子中,我们需要定义 schema.index 来创建我们的索引。请检查猫鼬文档索引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)
})
于 2021-07-24T01:04:13.317 回答
0

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

如果您将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;

于 2021-12-10T17:10:37.153 回答
0

在您的连接功能中不要忘记提及 useCreateIndex: true

mongoose.connect(url, {
  useNewUrlParser: true,
  useCreateIndex: true,
  useFindAndModify: false,
  useUnifiedTopology: true,
})
于 2022-02-08T17:19:38.513 回答