我试图让 MongoDB 根据其索引检测重复值。我认为这在 MongoDB 中是可能的,但是通过 Mongoose 包装器,事情似乎被破坏了。所以对于这样的事情:
User = new Schema ({
email: {type: String, index: {unique: true, dropDups: true}}
})
我可以使用相同的电子邮件保存 2 个用户。该死。
此处表达了相同的问题:https://github.com/LearnBoost/mongoose/issues/56,但该线程很旧并且无处可去。
现在,我手动调用数据库来查找用户。该电话并不昂贵,因为“电子邮件”已编入索引。但是让它在本地处理仍然很好。
有人对此有解决方案吗?
哎呀!你只需要重新启动 mongo。
哎呀!你只需要重新启动 mongo。
并重新索引,使用:
mongo <db-name>
> db.<collection-name>.reIndex()
在测试中,由于我没有重要数据,你也可以这样做:
mongo <db-name>
> db.dropDatabase()
我遇到了同样的问题:在已经将用户添加到数据库之后,我将 email
字段的唯一约束添加到了我们的 UserSchema
,并且仍然能够使用欺骗电子邮件保存用户。我通过执行以下操作解决了这个问题:
1)从用户集合中删除所有文档。
2) 从 mongo shell,执行命令:db.users.createIndex({email: 1}, {unique: true})
关于第 1 步,请注意来自 Mongo 的文档:
如果集合已经包含违反索引唯一约束的数据,则 MongoDB 无法在指定的索引字段上创建唯一索引。
https://docs.mongodb.com/manual/core/index-unique/
我做了这样的事情:
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
。
async Foo.createIndexes()
如果您在 Mongo 中留下了一些重复项,也会发生这种情况。当您的应用程序启动时,Mongoose 将尝试在 Mongo 中创建它们。
为防止这种情况,您可以通过以下方式处理此错误:
yourModel.on('index', function(err) {
if (err?) {
console.error(err)
}
);
好的,我可以通过在字段上添加索引并设置唯一属性来从 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\" }"
}
})
解决问题的步骤:
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次
根据文档:https://docs.mongodb.com/v2.6/tutorial/modify-an-index/
要修改现有索引,您需要删除并重新创建索引。
不要重新启动 MONGO !
1 - 删除集合
db.users.drop()
- 重新索引表
db.users.ensureIndex({email: 1, type: 1}, {unique: true})
Mongoose 在从应用程序级别强制执行唯一索引时有点松散;因此,最好使用 mongo cli 从数据库本身强制执行您的唯一索引,或者通过在 UserSchema 之后编写以下代码行来明确告诉 mongoose 您对 unique
索引很认真:
UserSchema.index({ username: 1, email: 1 }, { unique: true});
这将对您的 UserSchema 中的 username
和 email
字段强制执行唯一索引。干杯。
在以下情况下,Mongoose 将默默地无法添加唯一索引:
集合已经有同名的索引集合已经包含具有索引字段重复的文档
在第一种情况下,使用 db.collection.getIndexes()
列出索引,并使用 db.collection.dropIndex("index_name")
删除旧索引。当您重新启动 Mongoose 应用程序时,它应该正确添加新索引。
在第二种情况下,您需要在重新启动 Mongoose 应用程序之前删除重复项。
如何使用这个插件:
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中。
除了自动锁定集合或强制单个连接之外,没有真正的解决方案。
对于我们的大多数用户来说,这不是问题,但需要注意的边缘情况。
最新答案:根本不需要重启mongodb,如果colleciton已经有同名索引,mongoose不会再重新创建你的索引,所以,先删除colleciton现有的索引,现在,当你运行mongoose时,它会创建新的索引,以上过程解决了我的问题。
重新启动和使用插件对我来说不起作用,而且在我们确信 mongo 可以自己做的事情上使用插件有点矫枉过正。
所以这里是修复。在您的连接函数中将其添加到选项对象(第二个参数)
const options = {
autoIndex: true, //this is the code I added that solved it all
}
mongoose.connect(process.env.MONGO_URI, options);
您也可以通过删除索引来解决此问题;
假设您要从集合 users
和字段 username
中删除唯一索引,请输入:
db.users.dropIndex('username_1');
如果表/集合为空,则为该字段创建唯一索引:
db.<collection_name>.createIndex({'field':1}, {unique: true})
如果表/集合不为空,则删除集合并创建索引:
db.<collection_name>.drop()
db.<collection_name>.createIndex({'field':1}, {unique: true})
现在重新启动 mongoDB。
检查架构中的 autoIndex 是否为真,当您使用 mongoose.connect 选项时,它可能设置为假(默认为真)
我有一段时间遇到同样的问题并进行了大量搜索,我的解决方案是 createIndexes()
函数。
我希望这会有所帮助。
所以代码将是这样的。
User = new Schema ({
email: {type: String, unique: true}
});
User.createIndexes();
一个老问题,但对于仍然遇到此问题的任何人,您可能没有正确应用索引:
如果您将连接选项中的 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;
如果您在连接方法中使用选项 autoIndex: false
,如下所示:
mongoose.connect(CONNECTION_STRING, { autoIndex: false });
尝试删除它。如果这不起作用,请尝试按照此线程中的建议重新启动 mongodb。
您可以将架构定义为
User = new Schema ({
email: {
type: String,
unique: true
}
})
但是,当已经有一个文档并且之后您更改了用户的架构时,这可能不起作用。如果您不想删除该集合,您可以为此用户集合创建电子邮件索引。使用此命令,您可以在电子邮件上创建索引。
db.User.createIndex({email:1},{unique: true})
或者您可以删除集合并再次添加用户。对于删除集合,您可以输入:
db.User.drop()
当我遇到这个问题时,我尝试删除数据库,多次重新启动服务器(nodemon),但没有一个技巧根本不起作用。我通过 Robo 3T 找到了以下解决方法:
在 Robo 3T 中,双击数据库以打开收藏 打开收藏以显示相关收藏。确保您的集合是空的,首先右键单击索引文件夹。默认情况下,您将看到 _id_ 作为默认值。现在,选择 Add Index 选择一个名称,例如电子邮件字段的电子邮件,例如将键提供为 JSON。例如 { "email": 1 } 点击唯一复选框保存
这将确保没有重复的电子邮件保存在 MongoDB 中。
确保您的集合没有多余的字段,您刚刚放置了唯一索引。
然后只需重新启动您的应用程序(猫鼬)。它只是默默地添加索引失败。
从集合中删除所有文档:
db.users.remove({})
正如其他人提到的那样,重新启动对我有用
如果您的 MongoDB 正在作为服务工作(找到此问题的简单方法是,如果您不需要通过终端启动 mongod.exe 文件就不需要连接到数据库),那么在进行更改后,您可能需要重新启动服务和/或完全删除您的数据库。
这很奇怪,因为对于某些用户来说,只删除一个集合就可以了。其中一些只需要删除数据库。但那些对我不起作用。我删除了数据库,然后重新启动了 MongoDB Server 服务。
要重新启动服务,请在 Windows 搜索栏上搜索服务,然后找到 MongoDB 服务,双击打开然后停止并再次启动该服务。
如果其他方法对您不起作用,我相信这会起作用。
就我而言,猫鼬已经过时了。我通过在 CMD 上运行 npm outdated 来检查它。并更新了“猫鼬”。
请告诉你这是否也适用于你。
当您将数据库与应用程序连接时,添加此选项:“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”之类的解决方案,但对我不起作用。
在我的例子中,我们需要定义 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)
})
在您的连接功能中不要忘记提及 useCreateIndex: true
mongoose.connect(url, {
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false,
useUnifiedTopology: true,
})
您实际上不需要使用 '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");
}
}
}}
如果您没有指定自动索引数据,这意味着检查唯一性,猫鼬不会那样做
只需在连接到数据库时将它们设置为 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');
});