mongoDB 3.2中的唯一索引忽略空值
Posted
技术标签:
【中文标题】mongoDB 3.2中的唯一索引忽略空值【英文标题】:Unique index in mongoDB 3.2 ignoring null values 【发布时间】:2016-06-15 19:15:11 【问题描述】:我想将唯一索引添加到忽略唯一索引字段中的空值并忽略基于 partialFilterExpression 过滤的文档的字段。
问题是稀疏索引不能与部分索引一起使用。
此外,添加唯一索引会将空值添加到索引键字段,因此不能根据 PartialFilterExpression 中的 $exist 条件忽略文档。
在 MongoDB 3.2 中是否可以解决这种情况?
【问题讨论】:
空值在您的情况下有什么特殊含义吗?如果没有,您可以随时 $unset 为所有空值设置该字段,从而可以使用 $exist 运算符。 添加唯一索引自动添加空字段,因此我们不能拥有没有唯一索引键字段的文档。 【参考方案1】:我正在添加此答案,因为我正在寻找解决方案但没有找到。这可能不能完全回答这个问题,或者可能是,但会帮助很多像我这样的人。
示例。如果null
的字段是houseName
,并且是string
类型,解决办法可以是这样的
db.collectionName.createIndex(
name: 1, houseName: 1,
unique: true, partialFilterExpression: houseName: $type: "string"
);
这将忽略字段houseName
中的null
值,并且仍然是唯一的。
【讨论】:
只是我的测试中的一个注释,供其他任何寻求相同解决方案的人使用:虽然这可以作为一种在允许空值的同时强制唯一性的机制,但 Mongo 并未使用索引字段使用索引进行查找查询并使用 hint() 强制它导致性能非常缓慢 @PeteS 我看到了同样的行为,你找到可行的解决方案了吗? @MattOakley 不完全是。我们采用了一种解决方法,即在索引上设置 partialFilterExpression: fieldToIndex: $exists: true ,然后使用 [BsonIgnoreIfNull] (C#) 在应用程序代码中装饰我们类中的相应属性。如果保存时应用程序中的字段为空,Mongo 驱动程序将不会序列化该字段。 如果部分索引包含$type: string
,则应将其添加到查询中以使用索引(如.find( houseName: $type: "string", $eq: "some value" )
)
@PeteS 和@oryol 是正确的,在默认请求中使用$type: "string"
,不会提高性能,必须使用 $exists: true
【参考方案2】:
是的,您可以在 MongoDB 3.2 中创建部分索引
请看https://docs.mongodb.org/manual/core/index-partial/#index-type-partial
MongoDB 建议使用部分索引而不是稀疏索引。我会建议你放弃你的稀疏索引以支持部分索引。
【讨论】:
我必须使用 PartialFilterExpression 过滤数据以进行索引,并且必须使用唯一索引。 唯一的事情是我希望某些文档没有唯一的索引键字段,这似乎是不可能的,或者我可能不知道。【参考方案3】:您可以在 mongo:3.2 中创建部分索引。 例如,如果 ipaddress 可以是“”,但“127.0.0.1”应该是唯一的。解决办法可以是这样的:
db.collectionName.createIndex(
"ipaddress":1,
"unique":true, "partialIndexExpression":"ipaddress":"$gt":"")
这将忽略 ipaddress 字段中的“”值,并且仍然是唯一的
【讨论】:
【参考方案4】:“你的领域”: “$exists”:是的, "$gt" : "0", “$类型”:“字符串”
【讨论】:
如果您想要一个索引对于所有不等于空字符串或 null 的值都是唯一的,那么这个答案是完美的。【参考方案5】:要在 mongodbCompass 中创建,您必须将其编写为 JSON:
要查找支持的其他类型,请参阅this link。
【讨论】:
【参考方案6】:是的,这可能是部分过滤器表达式不能包含任何“非”过滤器的问题。
对于那些可能对此类索引的 C# 解决方案感兴趣的人,这里有一个示例。
我们有一个“用户”实体,它与“医生”实体具有一对一的“关系”。 此关系由“用户”实体中的非必需、可为空的字段“DoctorId”表示。换句话说,要求给定的“医生”一次只能链接到单个“用户”。
所以我们需要一个唯一的索引,当某些东西试图将 DoctorId 设置为已经为任何其他“用户”实体设置的相同 Guid 时,它可以触发异常。同时,“DoctorId”字段必须允许多个“null”条目,因为许多用户没有附加任何医生。
构建这种索引的解决方案如下:
var uniqueDoctorIdIndexDefinition = new IndexKeysDefinitionBuilder<User>()
.Ascending(o => o.DoctorId);
var existsFilter = Builders<User>.Filter.Exists(o => o.DoctorId);
var notNullFilter = Builders<User>.Filter.Type(o => o.DoctorId, BsonType.String);
var andFilter = Builders<User>.Filter.And(existsFilter, notNullFilter);
var createIndexOptions = new CreateIndexOptions<User>
Unique = true,
Name = UniqueDoctorIdIndexName,
PartialFilterExpression = andFilter,
;
var uniqueDoctorIdIndex = new CreateIndexModel<User>(
uniqueDoctorIdIndexDefinition,
createIndexOptions);
users.Indexes.CreateOne(uniqueDoctorIdIndex);
可能在您对“用户”实体的描述中,您必须通过使用属性直接指定“DoctorId”字段的 BsonType,例如在我们的例子中是:
[BsonRepresentation(BsonType.String)]
public Guid? DoctorId get; set;
我非常确定对于这个问题有一个更精通和紧凑的解决方案,所以如果有人在这里提出建议,我会很高兴。
【讨论】:
以上是关于mongoDB 3.2中的唯一索引忽略空值的主要内容,如果未能解决你的问题,请参考以下文章
MongoDB——索引属性之唯一索引(Unique Indexes)
MongoDB——索引属性之唯一索引(Unique Indexes)