我想知道是否有办法强制使用唯一的集合条目,但仅限于条目不为空。 Ë 示例模式:
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'选项崩溃(如果有不同的用户没有电子邮件)。
现在我正在应用程序级别解决它,但是希望保存该数据库查询。
THX
答案 0 :(得分:130)
从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
字段。
答案 1 :(得分:25)
是的,可以将多个文档的字段设置为null
或未定义,同时强制使用唯一的“实际”值。
要求:
string
时,始终为object
或null
。如果您对细节不感兴趣,请随时跳至implementation
部分。
要补充@ Nolan的答案,从MongoDB v3.2开始,您可以使用带有过滤表达式的部分唯一索引。
部分过滤器表达式有局限性。它只能包含以下内容:
- 等式表达式(即字段:值或使用
$eq
运算符),$exists: true
表达,$gt
,$gte
,$lt
,$lte
表达式,- 仅在顶层
$type
表达式,$and
运营商
这意味着无法使用普通表达式{"yourField"{$ne: null}}
。
但是,假设您的字段始终使用相同类型,则可以使用$type
expression。
{ field: { $type: <BSON type number> | <String alias> } }
MongoDB v3.6增加了对指定多种可能类型的支持,这些类型可以作为数组传递:
{ field: { $type: [ <BSON type1> , <BSON type2>, ... ] } }
这意味着当null
不是email
时,它允许该值为多种类型中的任意一种。
因此,如果我们希望允许下面示例中的string
字段接受binary data
或者$type
值,那么适当的{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"}}
}
}
});
您可以在mongoose架构中指定它:
User.collection.createIndex("email", {
unique: true,
partialFilterExpression: {
"email": {
$type: "string"
}
}
});
或直接将其添加到集合(使用本机node.js驱动程序):
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"}
}
})
null
这将允许使用<data>
<variable name="user" type="ObservableMap<String,Object>"/>
</data>
电子邮件插入多个记录,或者根本不插入电子邮件字段,但不能使用相同的电子邮件字符串。
答案 2 :(得分:4)
快速更新那些研究此主题的人。
所选答案可行,但您可能需要考虑使用部分索引。
在3.2版中更改:从MongoDB 3.2开始,MongoDB提供了 创建部分索引的选项。部分索引提供了超集 稀疏索引的功能。如果您使用的是MongoDB 3.2或 之后,部分索引应优先于稀疏索引。
更多doco部分索引:https://docs.mongodb.com/manual/core/index-partial/
答案 3 :(得分:2)
实际上,只有“电子邮件”字段不存在的第一个文档才能成功保存。不存在“email”的后续保存将在发出错误时失败(请参阅下面的代码段)。因此,请查看位于http://www.mongodb.org/display/DOCS/Indexes#Indexes-UniqueIndexes的有关唯一索引和缺失密钥的MongoDB官方文档。
// 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视为一个这样的值,则只能插入一次!通过在应用程序级别确保和验证它,您的方法是正确的。这就是它可以做到的。
您可能还想阅读此http://www.mongodb.org/display/DOCS/Querying+and+nulls