mongoDB 3.2中的唯一索引忽略空值

Nik*_*hil 14 database indexing mongodb

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

问题是稀疏索引不能与Partial索引一起使用.

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

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

myt*_*der 31

我正在寻找一个解决方案而没有找到一个解决方案,我正在添加这个答案.这可能无法回答这个问题或者可能是,但会像我一样帮助很多其他人.

例.如果字段为nullis houseName且类型为string,则解决方案可以是这样的

db.collectionName.createIndex(
   {name: 1, houseName: 1},
   {unique: true, partialFilterExpression: {houseName: {$type: "string"}}}
);
Run Code Online (Sandbox Code Playgroud)

这将忽略null字段中的值houseName并仍然是唯一的.

  • 只是我对其他任何寻找相同解决方案的测试的注意事项:尽管这是一种在允许空值的同时强制执行唯一性的机制,但Mongo没有使用索引进行查询查询,使用索引字段并使用hint()强制它导致表现非常缓慢 (4认同)
  • @MattOakley不完全是。我们采用了一种变通方法,即在索引上设置partialFilterExpression:{fieldToIndex:{$ exists:true}},然后使用[BsonIgnoreIfNull](C#)在应用代码中修饰我们类中的相应属性。保存时,如果应用程序中的字段为空,则Mongo驱动程序将不会序列化该字段。 (2认同)
  • 如果部分索引包含`$type: string`,您应该将其添加到您的查询中以使用索引(如`.find({ houseName: { $type: "string", $eq: "some value" } })`) (2认同)

jac*_*cob 8

这是我根据mongoDB 部分索引文档修改的示例:

db.contacts.createIndex(
   { email: 1 },
   { unique: true, partialFilterExpression: { email: { $exists: true } } }
)
Run Code Online (Sandbox Code Playgroud)

重要的

要使用部分索引,查询必须包含过滤表达式(或指定过滤表达式子集的修改过滤表达式)作为其查询条件的一部分。

您可以看到诸如以下的查询:

db.contacts.find({'email':'name@email.com'}).explain()
Run Code Online (Sandbox Code Playgroud)

将表明他们正在执行索引扫描,即使您没有指定,{$exists: true}因为您通过在过滤器中指定电子邮件来隐式指定partialFilterExpression的子集。

另一方面,以下查询将执行集合扫描:

db.contacts.find({email: {$exists: false}})
Run Code Online (Sandbox Code Playgroud)

警告

Mythicalcoder 的答案(目前投票最高的答案)非常具有误导性,因为它成功创建了唯一索引,但查询规划器通常无法使用您创建的索引,除非您将其添加到houseName: {$type: "string"}过滤器表达式中。这可能会产生您可能没有意识到的性能成本,并且可能会在以后引起问题。


Sal*_*eem 5

是的,您可以在MongoDB 3.2中创建部分索引

请参阅https://docs.mongodb.org/manual/core/index-partial/#index-type-partial

MongoDB建议使用部分索引而不是稀疏索引。我建议您放弃稀疏索引,转而使用部分索引。


小智 5

您可以在 mongo:3.2 中创建部分索引。例如,如果 ipaddress 可以是“”,但“127.0.0.1”应该是唯一的。解决方案可以是这样的:

db.collectionName.createIndex(
 {"ipaddress":1},
 {"unique":true, "partialIndexExpression":{"ipaddress":{"$gt":""}}})
Run Code Online (Sandbox Code Playgroud)

这将忽略 ipaddress 中的 "" 值并且仍然是唯一的