ChatGPT解决这个技术问题 Extra ChatGPT

猫鼬唯一索引不起作用!

我试图让 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/…

f
foobar

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


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

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

并重新索引,使用:

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

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

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

db.dropDatabase() 擦除您的数据库!
@IsaacPak 他漫不经心地说,就像是一些普通的手术一样😂
N
Neil Strain

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

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

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

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

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

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


如何删除某个索引?
s
solstice333

我做了这样的事情:

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

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

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


解决问题而不是围绕问题的问题的唯一答案。
这个答案帮助了我。我所缺少的只是要创建的唯一索引的 index: true
出于某种原因,传递 unique: true 有效,但作为索引: {...unique:true} dont.. ty
对我来说最相关的解决方案。我试图用重复的数据填充数据库,尽管添加了唯一索引,但 Mongoose 从未阻止我这样做。我现在明白必须在填充重复项之前显式创建索引,否则 mongoose 会跳过创建索引。请记住使其异步以完全完成索引:async Foo.createIndexes()
P
Pierre Maoui

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

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

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

w
woj.sierak

好的,我可以通过在字段上添加索引并设置唯一属性来从 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\" }"
    }
})

M
Manohar Reddy Poreddy

解决问题的步骤:

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(最后一行)

这是修复的简单方法 - 如果您已经有重复的值。

您还可以删除集合中的所有记录,以便唯一列(上面的名称)有重复值

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

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

autoIndex 选项设置为 true 不是必需的,默认为 true

不需要,默认为真

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

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

依次执行以上3个步骤如果您错过了什么,请执行2次

如果你错过了什么,做2次


D
Damien Romito

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

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

不要重新启动 MONGO !

1 - 删除集合

db.users.drop()

- 重新索引表

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

它说删除索引而不是集合
m
moeabdol

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

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

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


派对有点晚了,但是“在执行唯一索引时有点松散”的 ORM 有什么好处?
贬低无济于事的评论有什么好处。这个解决方案是可靠的并且可以生产。
D
Derek Hill

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

集合已经有同名的索引集合已经包含具有索引字段重复的文档

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

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


I
Isaac Pak

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) 附加选项

不区分大小写在您的架构中使用 uniqueCaseInsensitive 选项,即。 email: { type: String, index: true, unique: true, required: true, uniqueCaseInsensitive: true } 自定义错误信息,即。 exampleSchema.plugin(uniqueValidator, { message: '错误,期望 {PATH} 是唯一的。' });

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

注意事项(来自文档):

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

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

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


c
chen Jacky

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


J
Josef

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

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

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

A
Ademola Adegbuyi

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

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

db.users.dropIndex('username_1');


T
TrampolineTales

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

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

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

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

现在重新启动 mongoDB。


L
Lee Quinze

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


S
Samir Hosny

我有一段时间遇到同样的问题并进行了大量搜索,我的解决方案是 createIndexes() 函数。

我希望这会有所帮助。

所以代码将是这样的。

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

W
Waddah

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

如果您将连接选项中的 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;


R
Rafael Mejía

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

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

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


P
Pulkit Aggarwal

您可以将架构定义为

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

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

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

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

db.User.drop()

B
Balepur

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

在 Robo 3T 中,双击数据库以打开收藏 打开收藏以显示相关收藏。确保您的集合是空的,首先右键单击索引文件夹。默认情况下,您将看到 _id_ 作为默认值。现在,选择 Add Index 选择一个名称,例如电子邮件字段的电子邮件,例如将键提供为 JSON。例如 { "email": 1 } 点击唯一复选框保存

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


对象 { "email": 1 } 中的 1 是什么意思?
Z
Zero0Ho

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

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


S
StefanBob

从集合中删除所有文档:

db.users.remove({})

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


n
nick

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

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

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

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


n
nishant srivastava

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

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


你用的是什么版本?
H
Hasan

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


H
Henrique Van Klaveren

在我的例子中,我们需要定义 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)
})

P
Paul Roub

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

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

g
gimbeljw333

您实际上不需要使用 'unique: true' 或 mongoose-unique-validator 插件,您可以在使用 countDocuments() 的类型定义中简单地使用自定义 async validate():

在您的架构内...(假设您的架构用于用户模型)

email: {type: String, required: true, trim: true, lowercase: true, async validate(value) {
    const count = await mongoose.models.User.countDocuments({email: value});
    if (count > 0) {
        const existing = await  mongoose.models.User.findOne({email: value});
        if (!(existing._id.toString() === this._id.toString())) {
            throw new Error("Email not unique");
        }
    }
}}

A
Alaeddine

如果您没有指定自动索引数据,这意味着检查唯一性,猫鼬不会那样做

只需在连接到数据库时将它们设置为 true

mongoose.connect('connection url', {
    useUnifiedTopology: true,
    useNewUrlParser: true,
    useCreateIndex: true, //make this true
    autoIndex: true, //make this also true
})
.then(() => {
    console.log('Connected to mongoDB');
});