处理mongodb的唯一索引、稀疏索引和复合索引

15
由于mongodb将索引稀疏、包含一个或多个索引字段的复合索引, 这导致我的唯一性稀疏索引失败, 因为其中一个字段是可选的,并且由于索引目的被mongodb强制转换为null
我需要在数据库级别上确保这个字段和其他几个字段的组合的唯一性,而通过某些连接字符串在应用程序级别上管理这个问题让我感到担忧。
作为替代方案,我考虑将可能为空的索引字段的默认值设置为'null ' + anObjectId,因为这样可以让我保留索引而不会出现错误。这个方法是否可行(尽管有点hacky)?是否有更好的方法来强制执行复合索引的数据库级别的唯一性?
编辑:我被要求更详细地阐述实际的问题领域,所以在这里说一下。
我们从客户那里获取大量数据源,需要将其整合到我们的数据库中。这些源包含客户提供的三个不同的标识符,我们用它们来更新我们在数据库中存储的版本,以便在数据源刷新时使用。我需要将这些标识符的唯一性与客户绑定,因为相同的标识符可能来自多个来源,而我们希望允许这种情况发生。
文档结构如下:
{
  "identifiers": {
      "identifierA": ...,
      "identifierB": ...,
      "identifierC": ...
  },
  "client": ...
}

因为每个标识符都是可选的(至少需要其中三个中的一个),所以我需要唯一地索引与客户端的组合(例如,一个索引是由 client 加上 identifierA 组成)。但是,只有当标识符存在时,才能出现此索引,但这在mongodb中不受支持(请参见上面的超链接)。
我正在考虑上述解决方案,但我想听听其他人是否已经解决了这个问题或者有什么建议。

过于冗长且不清晰。尝试发布一些你想要实现的示例。 - Neil Lunn
1
你能解释一下为什么不清楚吗?我认为我表达得很明确了...
  1. 我想要在多个字段的组合上实现数据库级别的唯一性保证
  2. mongodb 不支持这个功能
  3. 我追加一个生成的 objectId 到一个字符串的解决方案有意义吗?
- jtmarmon
你似乎把问题局限在“展示如何创建索引”和“我认为这是正确的方法但不起作用”上了。我想给你一个机会解释一下你试图通过创建索引来解决的实际问题,因为更懂行的人可能知道另一种更好的方式。比hacky(指粗糙的编程)更好的方式? - Neil Lunn
@NeilLunn 请查看修改 :) - jtmarmon
我可以建议这里的问题是您在子文档中有“键”,而不是像[{ "type": "A", "data": "Something },{ "type": "B", "data": "Something else" }]这样使用文档数组。但这正是我所说的“解释实际问题”的含义。如果您告诉我们存储的数据类型,约束条件以及如何使用它,那么就可以清楚地看到解决问题的其他方法。 - Neil Lunn
啊,那是一个有趣的解决方案。我可能会这样做。我的阐述不清楚吗,还是你只是在详细说明你的阐述请求? - jtmarmon
3个回答

15

2
实际上,由于我们需要类似以下的内容:partialFilterExpression: { email: { $exists: true }, email : {$ne: null} },而您提出的方案不可行。 - ricardoespsanto
2
您的部分表达式无效。请使用 $and: [ {email: { $exists: true} }, email: {$ne: null}}]。 - dCoder
相同的错误信息:部分索引中的不支持的表达式:$not wristband == ""。我认为部分索引只支持等式运算符,而不支持不等式运算符,至少这是我从以下链接中读到的:https://docs.mongodb.com/manual/core/index-partial/。 - ricardoespsanto
1
你是正确的。你可以使用 $type - dCoder
2
搞定了!谢谢。简而言之:$type: "string" 意味着它是一个字符串并且存在,因此它会处理 null、undefined 和不存在的属性。 - ricardoespsanto
显示剩余2条评论

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.

然而,对于具有稀疏和唯一属性的单个索引字段,它按预期工作。

我觉得这是一个将在未来版本中修复的错误。

无论如何,这里有两种解决方法可以绕过这个问题:

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

function createHashForUniqueCheck(obj){
    if( obj.firstName && obj.id){
        return MD5( String( obj.firstName) + String(obj.id) );
    }
    return null;
}

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


0

你如何创建一个哈希复合索引? - dCoder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接