处理mongodb独特,稀疏,复合指数

jtm*_*mon 12 indexing unique mongodb

因为mongodb将索引包含一个或多个索引字段的稀疏复合索引,所以它导致我的唯一稀疏索引失败,因为其中一个字段是可选的,并且null由于mongodb为了索引而被强制转换.

对于这个领域和其他一些领域的组合,我需要数据库级别的唯一性保证,并且必须通过一些串联字符串来管理应用程序级别.

作为替代方案,我考虑将可能为空的索引字段的默认值设置为'null ' + anObjectId,因为它允许我保留索引而不会导致错误.这看起来像是一个敏感的(虽然是hacky)解决方案吗?有没有人知道我可以在复合索引上强制执行数据库级唯一性的更好方法?

编辑:我被要求详细说明实际的问题域,所以在这里.

我们从客户那里获得了需要集成到数据库中的大量数据.这些供稿包括客户提供的各种(3)唯一标识符,用于更新数据供稿刷新时存储在数据库中的版本.我需要将这些标识符的唯一性与客户联系起来,因为相同的标识符可能来自多个来源,我们希望允许这样做.

文档结构如下所示:

{
  "identifiers": {
      "identifierA": ...,
      "identifierB": ...,
      "identifierC": ...
  },
  "client": ...
}
Run Code Online (Sandbox Code Playgroud)

因为每个单独的标识符是可选的(需要三个中的至少一个),所以我需要唯一地索引索引与客户端的组合(例如,一个索引是client加号的组合identifierA).但是,此索引必须仅在标识符存在时发生,但我的mongodb不支持此(请参阅上面的超链接).

我正在考虑上述解决方案,但我想听听其他人是否解决了这个问题或有任何建议.

dCo*_*der 7

https://docs.mongodb.org/manual/core/index-partial/

从mongoDB 3.2开始,您也可以创建部分索引来支持它.

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

  • 实际上,因为我们需要类似的东西:partialFilterExpression: { email: { $exists: true }, email : {$ne: null} } 并且不支持您提出的建议不起作用 (2认同)
  • 您的部分表达式无效。使用 $and: [ {email: { $exists: true} }, email: {$ne: null}}] (2认同)
  • 这解决了它!谢谢。TL;DR: $type: "string" 意味着它是一个字符串并且存在,因此它会处理 null、未定义和不存在的属性 (2认同)

Lar*_*tle 3

稀疏索引可以避免对不存在的字段建立索引。唯一索引可避免插入具有相同字段值的文档。不幸的是,从 MongoDB 2.6.7 开始,即使在使用稀疏和唯一属性创建复合索引(索引两个或更多字段)时,也始终会强制执行唯一约束。

例子:

db = db.connect("test");
db.a.drop();
db.a.insert([
    {},
    {a : 1},
    {b : 1},
    {a : 1, b : 1}
]);
db.a.ensureIndex({a:1,b:1},  { sparse: true, unique: true } );
db.a.insert({a : 1}); // throws Error but wanted insert to be valid.
Run Code Online (Sandbox Code Playgroud)

但是,对于具有稀疏和唯一属性的单个索引字段,它可以按预期工作。我觉得这是一个错误,将在未来的版本中修复。

无论如何,这里有两个解决方案来解决这个问题。

1) 向每个文档添加一个非空哈希字段,仅当提供了用于检查唯一性的所有必需字段时才计算该字段。然后在哈希字段上创建稀疏唯一索引。

function createHashForUniqueCheck(obj){
    if( obj.firstName && obj.id){
        return MD5( String( obj.firstName) + String(obj.id) );
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

2) 在应用程序端,在插入 Mongodb 之前检查唯一性。:-)