MongoDB:嵌入式文档中的唯一键

时间:2010-12-14 03:38:29

标签: mongodb

是否可以为嵌入文档中的键设置唯一键?

我有一个包含以下示例文档的Users集合:

 {
       Name: "Bob",
       Items: [
           {
               Name: "Milk"
           },
           {
               Name: "Bread"
           }
       ]
    },
    {
       Name: "Jim"
    },

有没有办法在属性Items.Name?

上创建索引

当我尝试创建索引时出现以下错误:

> db.Users.ensureIndex({"Items.Name": 1}, {unique:true});
E11000 duplicate key error index: GroceryGuruApp.Users.$Items.Name_1  dup key: {
 : null }

有什么建议吗?谢谢!

5 个答案:

答案 0 :(得分:22)

唯一索引仅存在于集合中。要在文档中强制实施唯一性和其他约束,您必须在客户端代码中执行此操作。 (可能virtual collections允许这样做,你可以投票支持它。)

在您的情况下,您要做的是在密钥Items.Name上创建索引,这在任何文档中都不存在(它不引用数组Items中的嵌入文档)因此它是null并且违反了集合中的唯一约束。

答案 1 :(得分:7)

您可以创建唯一复合稀疏索引来完成您希望的内容。它可能不是最好的选择(客户端可能会更好),但它可以根据具体要求做你要求的。

要做到这一点,您需要在与Name: Bob相同的级别上创建另一个字段,该字段对于每个顶级记录都是唯一的(可以执行FirstName + LastName + Address,我们将调用此键{ {1}})。

然后创建一个这样的索引:

Identifier

稀疏索引会忽略没有该字段的项目,因此应解决您的ensureIndex({'Identifier':1, 'Items.name':1},{'unique':1, 'sparse':1}) 密钥问题。将您的唯一标识符和NULL组合为复合唯一索引应确保您不能每人两次使用相同的项目名称。

虽然我应该补充一点,我只和Mongo一起工作了几个月,而我的科学可能会被关闭。这不是基于经验证据,而是基于观察到的行为。

有关MongoDB索引的更多信息

答案 2 :(得分:3)

索引将覆盖所有用户,并且由于您要求它为“唯一”,因此没有用户可以拥有两个相同的命名项目,并且没有两个用户可以拥有相同的命名项目。

这就是你想要的吗?

此外,它似乎反对两个对Items.Name具有'null'值的用户,显然Jim确实如此,是否还有其他类似的记录?

在这样的索引集合上要求唯一性是不常见的。

MongoDB允许唯一索引,它只索引每个值的第一个,参见 http://www.mongodb.org/display/DOCS/Indexes#Indexes-DuplicateValues,但我怀疑真正的解决方案是在这种情况下不要求唯一性。

如果您只想在单个用户的Items中确保唯一性,您可能需要尝试$ addToSet选项。见http://www.mongodb.org/display/DOCS/Updating#Updating-%24addToSet

答案 3 :(得分:2)

另一种方法是将项目建模为散列,并将项目名称作为密钥。

Items: { "Milk": 1, "Bread": 1 }

我不确定您是在尝试将索引用于性能还是纯粹用于约束。正确的方法取决于您的使用案例,并确定原子操作是否足以保持数据的一致性。

答案 4 :(得分:1)

您可以使用findAndModify来创建序列/计数器功能。

function getNextSequence(name) {
   var ret = db.counters.findAndModify({
        query: { _id: name },
        update: { $inc: { seq: 1 } },
        new: true,
        upsert: true
    });
    return ret.seq;
}

然后每当需要新ID时使用它......

db.users.insert({
    _id: getNextSequence("userid"),
    name: "Sarah C."
})

这是http://docs.mongodb.org/manual/tutorial/create-an-auto-incrementing-field/。看看吧。