mongoDB/mongoose:如果不为空,则为唯一
我想知道是否有办法强制一个唯一的集合条目,但前提是条目不为null。 E 示例架构:mongoDB/mongoose:如果不为空,则为唯一,mongodb,node.js,mongoose,Mongodb,Node.js,Mongoose,我想知道是否有办法强制一个唯一的集合条目,但前提是条目不为null。 E 示例架构: var UsersSchema = new Schema({ name : {type: String, trim: true, index: true, required: true}, email : {type: String, trim: true, index: true, unique: true} }); 在这种情况下不需要“email”,但如果保存了“email”,我希望确保
var UsersSchema = new Schema({
name : {type: String, trim: true, index: true, required: true},
email : {type: String, trim: true, index: true, unique: true}
});
在这种情况下不需要“email”,但如果保存了“email”,我希望确保此条目是唯一的(在数据库级别)
空条目似乎获得值“null”,因此每个没有电子邮件的条目都会使用“unique”选项崩溃(如果有其他用户没有电子邮件)
现在,我正在应用程序级别上解决这个问题,但希望保存该db查询
thx实际上,只有不存在“email”as字段的第一个文档才能成功保存。不存在“电子邮件”的后续保存将在给出错误时失败(请参阅下面的代码段)。为此,请参阅MongoDB官方文档中关于唯一索引和缺少键的内容 根据定义,唯一索引只能允许一个值存储一次。如果你把NULL看作一个这样的值,它只能插入一次!通过在应用程序级别确保和验证方法,您的方法是正确的。这就是可以做到的
从MongoDB v1.8+开始,您可能还想阅读此,通过在定义索引时将
sparse
选项设置为true,您可以获得所需的行为,即确保值唯一,但允许多个文档不带字段。例如:
email : {type: String, trim: true, index: true, unique: true, sparse: true}
或者在外壳中:
db.users.ensureIndex({email: 1}, {unique: true, sparse: true});
请注意,唯一的稀疏索引仍然不允许多个具有电子邮件
字段且值为null
的文档,只允许多个没有电子邮件
字段的文档
请参见这只是对研究此主题的人员的快速更新 < >选定的答案将有效,但您可能需要考虑使用部分索引。 在版本3.2中更改:从MongoDB 3.2开始,MongoDB提供 选项创建部分索引。部分索引提供了 稀疏索引的功能。如果您使用的是MongoDB 3.2或 稍后,部分索引应该优先于稀疏索引 关于部分索引的更多文档:tl;博士 是的,可以有多个字段设置为
null
或未定义的文档,同时强制执行唯一的“实际”值
要求:
- MongoDB v3.2+李>
- 提前知道您的具体值类型(例如,在非
时始终是null
或字符串
)对象
实现部分
较长版本
为了补充@Nolan的答案,从MongoDB v3.2开始,您可以使用带有过滤器表达式的部分唯一索引
偏滤器表达式有一些限制。它只能包括以下内容:
- 相等表达式(即字段:值或使用
$eq
运算符)
$exists:true
表达式
$gt
,$gte
,$lt
,$lte
表达式
$type
表达式
$和
操作员仅在顶层
这意味着不能使用普通表达式{“yourField”{$ne:null}
但是,假设字段始终使用相同的类型,则可以使用
实施
猫鼬
您可以在mongoose模式中指定它:
const UsersSchema = new Schema({
name: {type: String, trim: true, index: true, required: true},
email: {
type: String, trim: true, index: {
unique: true,
partialFilterExpression: {email: {$type: "string"}}
}
}
});
或者直接将其添加到集合(使用native node.js驱动程序):
本机mongodb驱动程序
使用
mongodb外壳
使用:
这将允许插入带有null
电子邮件的多个记录,或者根本没有电子邮件字段,但不具有相同的电子邮件字符串。Awesome!绝对是像我这样的新手在1.8之后的最佳答案!注意:如果只在模式中添加一个sparse:true,Mongoose不会将您的唯一索引更新为稀疏索引。您必须删除并重新添加索引。不知道这是预期的还是错误。“注意:如果数据库上已经存在索引,它将不会被替换。”-我认为这并不能正确回答问题,因为一些没有特定字段的文档与一些在该字段上有空值(不能唯一索引)的文档不同。@kako nawao这是真的,它只适用于没有email
字段的文档,而不适用于实际存在null
值的文档。请参阅更新的答案。不适用于缺少的字段。可能在以后版本的mongodb中行为发生了变化。答案应该更新。很棒的答案。你是救世主。这个答案对我来说也是如此。这个问题的大多数公认答案都涉及到确保你没有显式地为索引键设置空值。相反,它们被未定义地传递。我正在这样做,但仍然会出错(使用unique
和sparse
)。我用这个答案更新了我的模式,删除了我现有的索引,它就像一个符咒一样工作。投票选了这个,因为它提供了知识和可能的答案,基于最常见的场景,人们首先会得到这个答案。谢谢你的详细回答!:+1:
{ field: { $type: <BSON type number> | <String alias> } }
{ field: { $type: [ <BSON type1> , <BSON type2>, ... ] } }
{email: {$type: ["string", "binData"]}}
const UsersSchema = new Schema({
name: {type: String, trim: true, index: true, required: true},
email: {
type: String, trim: true, index: {
unique: true,
partialFilterExpression: {email: {$type: "string"}}
}
}
});
User.collection.createIndex("email", {
unique: true,
partialFilterExpression: {
"email": {
$type: "string"
}
}
});
db.collection('users').createIndex({
"email": 1
}, {
unique: true,
partialFilterExpression: {
"email": {
$type: "string"
}
}
},
function (err, results) {
// ...
}
);
db.users.createIndex({
"email": 1
}, {
unique: true,
partialFilterExpression: {
"email": {$type: "string"}
}
})