MongoDB/monose: 如果不为空则为唯一

我想知道是否有办法强制一个唯一的集合条目 但只有当条目不为空时。 你好 示例模式:

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”,所以每个没有电子邮件的条目都会崩溃,并出现“惟一”选项(如果有一个不同的用户没有电子邮件)。

现在我正在应用程序级别上解决这个问题,但是希望能够保存这个 db 查询。

谢谢

54704 次浏览

实际上,只有第一个文档中“ 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

从 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});

注意,一个唯一的、稀疏的索引仍然不允许多个文档使用 email字段,价值字段为 null,只允许多个文档使用 没有字段和 email字段。

参见 http://docs.mongodb.org/manual/core/index-sparse/

只是对那些研究这个话题的人的一个简短的更新。

所选择的答案将起作用,但您可能需要考虑使用部分索引。

在版本3.2中更改: 从 MongoDB 3.2开始,MongoDB 提供了 选项来创建部分索引。部分索引提供 稀疏索引的功能。如果您使用 MongoDB 3.2或 稍后,部分索引应优先于稀疏索引。

关于部分索引的更多 doco: https://docs.mongodb.com/manual/core/index-partial/

博士

是的,在执行唯一的“实际”值的同时,可以有多个字段设置为 null或未定义的文档。

要求 :

  • MongoDB v3.2 + .
  • 提前知道具体的值类型(例如,当不是 null时,始终是 stringobject)。

如果您对细节不感兴趣,可以直接跳到 implementation部分。

更长的版本

为了补充@Nolan 的回答,从 MongoDB v3.2开始,您可以使用带有过滤器表达式的部分唯一索引。

部分筛选器表达式有局限性。它只能包括以下内容:

  • 相等表达式(即字段: 值或使用 $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"]}}

实施

猫鼬

您可以在猫鼬模式中指定它:

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"
}
}
});

土生土长的蒙哥布司机

使用 collection.createIndex

db.collection('users').createIndex({
"email": 1
}, {
unique: true,
partialFilterExpression: {
"email": {
$type: "string"
}
}
},
function (err, results) {
// ...
}
);

蒙哥贝贝壳

使用 db.collection.createIndex:

db.users.createIndex({
"email": 1
}, {
unique: true,
partialFilterExpression: {
"email": {$type: "string"}
}
})

这将允许插入具有 null电子邮件的多条记录,或者根本不具有电子邮件字段,但不具有相同的电子邮件字符串。