Database 使用部分多键唯一索引时E11000(DuplicateKey)错误
考虑包含以下文档的集合:Database 使用部分多键唯一索引时E11000(DuplicateKey)错误,database,mongodb,indexing,nosql,unique-constraint,Database,Mongodb,Indexing,Nosql,Unique Constraint,考虑包含以下文档的集合: { name: "John Doe", emails: [ { value: "some@domain.com", isValid: true, isPreferred: true } ] }, { name: "John Doe", emails: [ { value: "john.doe@
{
name: "John Doe",
emails: [
{
value: "some@domain.com",
isValid: true,
isPreferred: true
}
]
},
{
name: "John Doe",
emails: [
{
value: "john.doe@gmail.com",
isValid: false,
isPreferred: false
},
{
value: "john.doe@domain.com",
isValid: true,
isPreferred: true
}
]
}
应该没有用户拥有相同的有效和首选电子邮件,因此有一个唯一的索引:
db.users.createIndex( { "emails.value": 1 }, { name: "loginEmail", unique: true, partialFilterExpression: { "emails.isValid": true, "emails.isPreferred": true } } )
将以下电子邮件添加到第一个文档会触发唯一约束冲突:
{
name: "John Doe",
emails: [
{
value: "john.doe@gmail.com",
isValid: false,
isPreferred: false
}
]
}
原因:com.mongodb.MongoCommandException:命令失败
错误11000(重复密钥):“E11000重复密钥错误集合:
profiles.users索引:loginEmail dup键:{emails.value:
“约翰。doe@gmail.com,emails.isValid:false,emails.isPreferred:false
}'on server profiles db mongodb.dev:27017。全部答复是:
{“ok”:0.0,“errmsg”:“E11000重复密钥错误集合:
profiles.users索引:loginEmail dup键:{emails.value:
“约翰。doe@gmail.com,emails.isValid:false,emails.isPreferred:
false},“code”:11000,“codeName”:“DuplicateKey”,“keyPattern”:
{“emails.value”:1,“emails.isValid”:1,“emails.isPreferred”:1},
“keyValue”:{“emails.value”:“john。doe@gmail.com“,“emails.isValid”:
false,“emails.isPreferred”:false}
正如我所理解的,之所以会发生这种情况,是因为过滤器表达式应用于集合,而不是嵌入文档,因此尽管有点违反直觉和出乎意料,但索引的行为如所述
我的问题是如何确保部分唯一性而不出现假阴性?TLDR:你不能
让我们先了解为什么会发生这样的事情,也许然后我们就会明白我们能做些什么。问题源于两个Mongo特性的组合
“emails.isPreferred”:true
)。但是,当您想开始使用子文档时,例如在您的案例中,您需要使用一些类似的内容,例如,的限制非常严格,并且没有给您这样的权限。
这意味着即使是带有电子邮件的文档,例如:电子邮件创建唯一索引
因此,由于所有这些“特性”和部分过滤器语法使用的限制,我们无法真正实现您想要的
那你能做什么呢?我相信你已经在考虑解决这个问题的办法了。一个简单的解决方案是维护一个额外的字段,该字段只包含那些isValid
和isPreferred
电子邮件。然后,一个唯一的稀疏索引就可以做到这一点
{
"_id": ObjectId("5f106c0e823eea49427eea64"),
"name": "John Doe",
"emails": [
{
"value": "john.doe@gmail.com",
"isValid": true,
"isPreferred": false
},
{
"value": "john.doe@domain.com",
"isValid": false,
"isPreferred": true
}
]
}