【问题标题】:Unique index in mongoDB 3.2 ignoring null valuesmongoDB 3.2中的唯一索引忽略空值
【发布时间】:2016-06-15 19:15:11
【问题描述】:

我想将唯一索引添加到忽略唯一索引字段中的空值并忽略基于 partialFilterExpression 过滤的文档的字段。

问题是稀疏索引不能与部分索引一起使用。

此外,添加唯一索引会将空值添加到索引键字段,因此不能根据 PartialFilterExpression 中的 $exist 条件忽略文档。

在 MongoDB 3.2 中是否可以解决这种情况?

【问题讨论】:

  • 空值在您的情况下有什么特殊含义吗?如果没有,您可以随时 $unset 为所有空值设置该字段,从而可以使用 $exist 运算符。
  • 添加唯一索引自动添加空字段,因此我们不能拥有没有唯一索引键字段的文档。

标签: mongodb indexing database


【解决方案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; }
      

      我非常确定对于这个问题有一个更精通和紧凑的解决方案,所以如果有人在这里提出建议,我会很高兴。

      【讨论】:

        猜你喜欢
        • 2013-05-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-21
        • 1970-01-01
        • 1970-01-01
        • 2016-10-28
        • 1970-01-01
        相关资源
        最近更新 更多