猫鼬唯一索引不起作用!


95

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

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

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

此处已表达了相同的问题:https : //github.com/LearnBoost/mongoose/issues/56,但是该线程很旧,导致无处可去。

现在,我正在手动调用数据库以查找用户。由于对“电子邮件”进行了索引,因此该调用并不昂贵。但是让它在本地处理仍然会很好。

有人对此有解决方案吗?


1
坏消息,它仍然是mongod v2.4.3,mongoose v3.6.20的问题
阻尼帽

唯一性似乎可以在我的一台主机上工作,但是无法在另一台主机上使用完全相同的节点/猫鼬代码来强制执行唯一性。可以正常运行的主机运行单个mongod 3.4.10,而不运行单个mongod 3.4.10,运行运行mongod 3.2.17的副本集。在这两个主机上,我都是从头开始创建一个集合,因此现有的复制不是问题。我已经尝试过此页面上的大多数解决方案,并且有效的解决方案是@Isaac Pak的mongoose-unique-validator。
Maksym

Answers:


95

糟糕!您只需要重新启动mongo。


4
我遇到了同样的问题,但是我找不到如何在OSX上重新启动mongo的方法。当我终止该进程时,它将再次自动产生,并且唯一索引仍然不起作用...有什么想法吗?
ragulka 2012年

7
你是什​​么意思“哎呀,你只需要重启mongo” ?!您是说在不关闭数据库的情况下添加索引是不可能的吗?
andrewrk

7
这不是真的 您无需重新启动mongo即可添加索引。
JohnnyHK

1
为独特的事情..我不得不重启mongo ..并且它起作用了..谢谢!
穆罕默德·艾哈桑·阿亚兹

2
我尝试重新启动。也重新索引。不得不删除数据库来解决这个问题。猜测问题是添加索引之前已经存在重复项,因此在生产数据库中,我需要删除重复项然后重新启动?
isimmons 2015年

40

糟糕!您只需要重新启动mongo。

并使用以下方法重新编制索引:

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

在测试中,由于我没有重要数据,因此您也可以执行以下操作:

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

16
db.dropDatabase()擦除数据库!
艾萨克·帕克

28

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

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

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

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

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

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


11

如果您在Mongo中保留了一些重复项,也会发生此行为。当您的应用程序启动时,Mongoose会尝试在Mongo中创建它们。

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

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

10

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

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

外壳程序应该以这种方式响应:

{
    "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\" }"
    }
})

10

我做了这样的事情:

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似乎工作正常


该问题的唯一答案是解决问题而不是围绕问题展开。
Saksham Gupta

这个答案帮助了我。我所缺少的只是index: true要创建我的唯一索引。
ELCID


5

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

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

这将在UserSchema中的usernameemail字段上强制使用唯一索引。干杯。


5
派对晚了一点,但是ORM的好处是“强制执行唯一索引时有点松动”
Imre_G

轻浮的评论毫无用处,这有什么用。该解决方案是可靠的并且已可以生产。
艾萨克·朴

4

当出现以下情况之一时,猫鼬将无声地添加唯一索引:

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

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

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


3

猫鼬唯一验证器

如何使用此插件:

1)npm install-保存猫鼬唯一验证器

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

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

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


2

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


1

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

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

db.users.dropIndex('username_1');


1

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

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

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

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

现在重新启动mongoDB。


1

检查模式中的autoIndex是否为true,使用mongoose.connect选项时可能将其设置为false(默认为true)


1

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

希望对您有所帮助。

因此代码将像这样。

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

0

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

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

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


0

您可以将架构定义为

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

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

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

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

db.User.drop()

0

遇到此问题时,我尝试删除数据库,并多次重新启动服务器(nodemon),但所有技巧都没有用。通过Robo 3T,我发现以下解决方法:

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

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

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


对象{“ email”:1}中1的含义是什么?
siluveru kiran kumar

0

确保您的集合没有多余的字段,只需将唯一索引置于该字段即可。

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


0

从集合中删除所有文档:

db.users.remove({})

正如其他人所述,重新启动对我有用


0

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

这很奇怪,因为对于某些用户而言,只需删除一个集合即可。其中一些只需要删除数据库。但是这些对我没有用。我删除了数据库,然后重新启动了MongoDB Server服务。

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

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


0

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

请告诉它是否对您也有效。


您使用的是哪个版本?
Baboo_

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”之类的解决方案,但对我不起作用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.