mongoDB / 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} });
在这种情况下,“电子邮件”不是必需的,但如果保存“电子邮件”,我想确保此项是唯一的(在数据库级别)。
空条目似乎得到的值为'空',所以没有电子邮件崩溃与'唯一'选项(如果有一个不同的用户没有电子邮件)每个条目。
现在我正在解决它的应用程序级别,但很想保存数据库查询。
谢谢
从MongoDB v1.8 +开始,您可以获得确保唯一值的所需行为,但通过在定义索引时将sparse
选项设置为true,允许在没有该字段的情况下使用多个文档。 如:
email : {type: String, trim: true, index: true, unique: true, sparse: true}
或者在shell中:
db.users.ensureIndex({email: 1}, {unique: true, sparse: true});
请注意,唯一的稀疏索引仍然不允许多个email
字段值为 null
文档,只有多个文档没有 email
字段。
TL;博士
是的,可以做到。
将该字段设置为null
或未定义的多个文档,同时强制实施唯一的“实际”值。
要求 :
- MongoDB v3.2 +。
- 当你的字段有一个实际的值,它应该是一个特定的types(例如,总是一个string)。
怎么样? 转到下面的实现细节。
更长的版本
为了补充@Nolan的回答,从MongoDB v3.2开始,你可以使用带有过滤expression式的部分唯一索引。
部分过滤expression式有局限性。 它只能包括以下内容:
- 相等expression式(即字段:值或使用
$eq
运算符),$exists: true
expression式,$gt
,$gte
,$lt
,$lte
expression式,$type
expression式,$and
操作员只在顶层
这意味着不能使用简单的expression式{"yourField"{$ne: null}}
。
但是,假设您的字段总是使用相同的types ,则可以使用$type
expression式 。
{ field: { $type: <BSON type number> | <String alias> } }
履行
mongoose
你可以在一个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'}} } } });
或直接将其添加到集合(使用本机node.js驱动程序):
User.collection.createIndex("email", { unique: true, partialFilterExpression: { "email": { $type: "string" } } });
本机的mongodb驱动程序
使用collection.createIndex
db.collection('users').createIndex({ "email": 1 }, { unique: true, partialFilterExpression: { "email": { $type: "string" } } }, function (err, results) { // ... } );
mongodbshell
使用db.collection.createIndex
:
db.users.createIndex({ "email": 1 }, { unique: true, partialFilterExpression: { "email": {$type: "string"} } })
这将允许用null
电子邮件插入多个logging,或根本没有电子邮件字段,但不能使用相同的电子邮件string。
实际上,只有第一个“email”字段不存在的文件才能成功保存。 随后的保存“email”不存在的地方将会出错(见下面的代码段)。 出于这个原因,在http://www.mongodb.org/display/DOCS/Indexes#Indexes-UniqueIndexes处查看MongoDB官方文档中关于Unique Indexes和Missing Keys的内容。
// NOTE: Code to executed in mongo console. db.things.ensureIndex({firstname: 1}, {unique: true}); db.things.save({lastname: "Smith"}); // Next operation will fail because of the unique index on firstname. db.things.save({lastname: "Jones"});
根据定义,唯一索引只能允许一个值只存储一次。 如果你认为null是一个这样的值,它只能被插入一次! 通过在应用程序级别确保和validation您的方法,您是正确的。 这是如何做到的。
您也可以阅读http://www.mongodb.org/display/DOCS/Querying+and+nulls
只是对那些研究这个主题的快速更新。
选定的答案将起作用,但您可能需要考虑使用部分索引。
在版本3.2中更改:从MongoDB 3.2开始,MongoDB提供了创build部分索引的选项。 部分索引提供了稀疏索引function的超集。 如果您使用的是MongoDB 3.2或更高版本,则部分索引应优先于稀疏索引。
更多关于部分索引的doco: https ://docs.mongodb.com/manual/core/index-partial/