详解 Mongoose 中的 unique 唯一索引
unique
选项告诉 Mongoose 每个文档对于给定路径必须具有唯一值。例如下面是如何告诉 Mongoose 用户的 email
必须是唯一的。
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
email: {
type: String,
unique: true // `email` must be unique
}
});
const User = mongoose.model('User', userSchema);
如果您尝试创建两个相同的用户 email
,你会得到一个 重复键错误 。
// Throws `MongoError: E11000 duplicate key error collection...`
await User.create([
{ email: 'test@google.com' },
{ email: 'test@google.com' }
]);
const doc = new User({ email: 'test@google.com' });
// Throws `MongoError: E11000 duplicate key error collection...`
await doc.save();
更新也可能引发重复键错误。 如果您创建具有唯一电子邮件地址的用户,然后将其电子邮件地址更新为非唯一值,您将收到相同的错误。
await User.create({ email: 'test2@google.com' });
// Throws `MongoError: E11000 duplicate key error collection...`
await User.updateOne({ email: 'test2@google.com' }, { email: 'test@google.com' });
索引,不是验证器
一个常见的问题是 unique
选项告诉 Mongoose 定义一个 唯一索引 。 这意味着 Mongoose 不会 检查唯一性 validate()
。
await User.create({ email: 'sergey@google.com' });
const doc = new User({ email: 'sergey@google.com' });
await doc.validate(); // Does not throw an error
事实是 unique
定义索引而不是验证器也很重要,编写自动化测试。 如果你删除数据库 User
模型已连接,您还将删除 unique
索引,您将能够保存重复项。
await mongoose.connection.dropDatabase();
// Succeeds because the `unique` index is gone!
await User.create([
{ email: 'sergey@google.com' },
{ email: 'sergey@google.com' }
]);
在生产中,您通常不会删除数据库,因此这在生产中很少出现问题。
在编写 Mongoose 测试时,我们通常建议使用 deleteMany()
清除测试之间的数据,而不是 dropDatabase()
,这可确保您删除所有文档,而无需清除数据库级别的配置,例如索引和排序规则。 deleteMany()
也比 dropDatabase()
。
但是,如果您选择在测试之间删除数据库,则可以使用 Model.syncIndexes()
函数 重建所有唯一索引的
await mongoose.connection.dropDatabase();
// Rebuild all indexes
await User.syncIndexes();
// Throws `MongoError: E11000 duplicate key error collection...`
await User.create([
{ email: 'sergey@google.com' },
{ email: 'sergey@google.com' }
]);
处理 null
值
自从 null
是一个不同的值,您不能保存两个具有 null
电子邮件。 同样,您不能保存两个没有 email
值。
// Throws because both documents have undefined `email`
await User.create([
{},
{}
]);
// Throws because both documents have null `email`
await User.create([
{ email: null },
{ email: null }
]);
一种解决方法是使 email
财产 required
,这不允许 null
和 undefined
:
const userSchema = new mongoose.Schema({
email: {
type: String,
required: true,
unique: true // `email` must be unique
}
});
如果你需要 email
是唯一的 ,除非 它没有被定义,你可以改为定义一个 稀疏的唯一 索引 email
如下所示。
const userSchema = new mongoose.Schema({
email: {
type: String,
// `email` must be unique, unless it isn't defined
index: { unique: true, sparse: true }
}
});
用户友好的重复键错误
要使 MongoDB E11000 错误消息对用户友好,您应该使用 mongoose -beautiful-unique-validation 插件 。
const schema = new Schema({ name: String });
schema.plugin(require('mongoose-beautiful-unique-validation'));
const CharacterModel = mongoose.model('Character', schema);
const doc = await CharacterModel.create({ name: 'Jon Snow' });
try {
// Try to create a document with the same `_id`. This will always fail
// because MongoDB collections always have a unique index on `_id`.
await CharacterModel.create(Object.assign({}, doc.toObject()));
} catch (error) {
// Path `_id` (5cc60c5603a95a15cfb9204d) is not unique.
error.errors['_id'].message;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论