简短版
在MongoDB v3.2+ 中,你可以使用部分唯一索引和筛选表达式来实现多个字段为 null
或未定义时,强制实际值的唯一性。
要求:
- 提前知道具体值类型 (例如,非
null
时始终是 string
或 object
)。
如果您不想了解详情,请跳至implementation
部分。
详细版
补充 @Nolan's 的回答,从MongoDB v3.2开始,你可以使用带有过滤表达式的部分唯一索引。
部分过滤表达式有限制。只能包括以下内容:
- 相等表达式(即 field: value 或使用 $eq 运算符),
$exists: true
表达式,
$gt
, $gte
, $lt
, $lte
表达式,
$type
表达式,
$and
运算符仅在顶层可用
这意味着无法使用简单的表达式 {"yourField"{$ne: null}}
。
但是,假设你的字段始终使用相同的类型,你可以使用$type
表达式。
{ 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"]}}
实现
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) {
}
);
MongoDB Shell
使用 db.collection.createIndex
方法:
db.users.createIndex({
"email": 1
}, {
unique: true,
partialFilterExpression: {
"email": {$type: "string"}
}
})
这将允许插入多条记录,其中包含一个null
的电子邮件或没有电子邮件字段,但不允许插入具有相同电子邮件字符串的记录。
email
字段的文档,而不是实际上有一个值为null
的字段。请查看更新后的答案。 - JohnnyHK