【问题标题】:MongoDB Optional Unique IndexMongoDB 可选唯一索引
【发布时间】:2016-03-03 11:09:30
【问题描述】:

我有一个供用户使用的 MongoDB 架构,看起来像这样:

{
  userId: "some-string",
  anonymousId: "some-other-string",
  project: {"$oid": "56d06bb6d9f75035956fa7ba"}
}

用户必须拥有userIdanonymousId。由于用户属于一个项目,该模型还有一个名为 project 的引用,它链接到项目集合。

每个项目的任何userIdanonymousId 值都必须是唯一的,因此我创建了两个复合索引,如下所示:

db.users.createIndex({ "userId": 1, "project": 1 }, { unique: true })
db.users.createIndex({ "anonymousId": 1, "project": 1 }, { unique: true })

但是,由于不必同时提供 userIdanonymousId,而是只提供其中一个,MongoDB 会为 null 值抛出 duplicate key 错误(例如,如果第二个用户提供了匿名 ID 但没有用户 ID)。

因此,我尝试将sparse: true 标志添加到复合索引,但这显然只有在两个字段都为空时才有效。我还尝试将稀疏标志仅添加到字段而不是复合索引,但这也不起作用。

举个例子,假设我在集合中有以下三个用户:

{ userId: "user1", anonymousId: null, project: {"$oid": "56d06bb6d9f75035956fa7ba"}}

{ userId: "user2", anonymousId: "anonym", project: {"$oid": "56d06bb6d9f75035956fa7ba"}}

{ userId: "user3", anonymousId: "random", project: {"$oid": "56d06bb6d9f75035956fa7ba"}}

以下应该是可能的:

  • 我希望能够为同一个项目插入另一个用户 {userId: "user4", anonymousId: null}(不会出现重复键错误)
  • 但是,如果我尝试使用 {userId: "user3"} 插入另一个用户或使用 {anonymousId: "random"} 插入另一个用户,则应该会出现重复键错误

我还能如何做到这一点?

【问题讨论】:

  • 您使用的是哪个版本的 MongoDB?
  • 我使用的是 3.0.9。你问是因为部分索引吗?
  • 确实如此。这是意图,将解决您的许多问题。如果可能的话,我会建议升级数据库引擎。

标签: mongodb indexing


【解决方案1】:

如果您使用的是 MongoDB 3.2,则可以使用 唯一部分索引 代替稀疏索引。

部分索引实际上比稀疏索引更推荐

示例

db.users.createIndex({ "userId": 1, "project": 1 }, 
{ unique: true, partialFilterExpression:{ 
  userId: { $exists: true, $gt : { $type : 10 } } } })

db.users.createIndex({ "anonymousId": 1, "project": 1 }, 
{ unique: true, partialFilterExpression:{ 
  anonymouseId: { $exists: true, $gt : { $type : 10 } } } })

在上面的例子中,只有当userId 存在并且不包含空值时才会创建唯一索引。 anonymousId 也是如此。

请看https://docs.mongodb.org/manual/core/index-unique/#unique-partial-indexes

【讨论】:

  • 是的,我知道,但不幸的是我必须使用 3.0.9 版本。但是,您将如何使用部分索引来做到这一点?
  • 那么在这种情况下,您只有一个选项,我看到 profesor79 在上面发布。在所有三个字段上创建复合索引。
  • 您能否编辑您的答案以举例说明在这种情况下如何创建唯一的部分索引?
  • 当然,您能否更新您的问题并发布涵盖您要解决的案例的示例文档。
  • imho 部分索引在这种情况下也会有同样的弱点——因为需要一个业务逻辑来处理多个匿名 ID,然后创建一个真实的用户 ID
【解决方案2】:

索引 a,c - 不能像唯一一样稀疏.....

索引 b,c - 不能像唯一一样稀疏.....

索引 a,b,c 怎么样?

db.benjiman.insert( { userId: "some-string", anonymousId: “其他字符串”,项目:{“_oid”:“56d06bb6d9f75035956fa7ba”} })

db.benjiman.insert( { userId: "some-string2", project: {"_oid": "56d06bb6d9f75035956fa7ba"} })

db.benjiman.insert( { anonymousId: "some-other-string2", 项目: {"_oid": "56d06bb6d9f75035956fa7ba"} })

db.benjiman.createIndex({ "userId": 1, "anonymousId": 1, "project": 1 }, { unique: true })

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2012-03-24
  • 1970-01-01
  • 2016-10-28
  • 2013-06-12
  • 1970-01-01
  • 1970-01-01
  • 2015-02-15
  • 2012-09-03
相关资源
最近更新 更多