2011-07-19 59 views
18

唯一索引我有一个类似的结构:的MongoDB:对数组元素的属性

class Cat { 
    int id; 
    List<Kitten> kittens; 
} 

class Kitten { 
    int id; 
} 

我想阻止用户使用一个以上的小猫用相同的ID创建一只猫。我试图创建一个索引如下:

db.Cats.ensureIndex({'id': 1, 'kittens.id': 1}, {unique:true}) 

但是,当我试图插入一个格式错误的猫,Mongo接受它。

我错过了什么吗?这甚至可以完成?

+1

参见http://stackoverflow.com/questions/4435637/mongodb-unique-key-in-embedded-document/4437836 – pingw33n

回答

24

据我所知,唯一索引只执行跨越不同文件的唯一性,所以这将抛出一个重复键错误:

db.cats.insert({ id: 123, kittens: [ { id: 456 } ] }) 
db.cats.insert({ id: 123, kittens: [ { id: 456 } ] }) 

但是,这是可以的:

db.cats.insert({ id: 123, kittens: [ { id: 456 }, { id: 456 } ] }) 

我不知道是否有任何方法可以在Mongo级别强制实施您需要的约束,也许这是您在插入更新时可以在应用程序逻辑中检查的内容?

+1

不幸的是它看起来你是对的 - 我必须在代码中执行此操作。好吧。 –

+6

太伤心了! :(。应该有一个选项来确保文件数组中的唯一性 –

+0

你可以做的是在保存数组时确保它是唯一的写验证钩子 –

21

确保各个值的唯一性阵列中的场

除了上述的例子中,有在MongoDB中的功能,以确保当要添加新的对象/值对的数组字段,只有当值/对象不存在时才会执行更新。

所以,如果你有一个文件,看起来像这样:

{ _id: 123, kittens: [456] } 

这将被允许:导致

{ _id: 123, kittens: [456, 456] } 

db.cats.update({_id:123}, {$push: {kittens:456}}) 

但是使用$ addToSet功能(相对于$ pu sh)会在添加之前检查该值是否已经存在。 所以,起始号码:

{ _id: 123, kittens: [456] } 

然后执行:

db.cats.update({_id:123}, {$addToSet: {kittens:456}}) 

不会有任何影响。

因此,长话短说,唯一约束不会验证数组字段值项中的唯一性,只是两个文档在索引字段中不能具有相同的值。

1

在数组属性中有一个与插入具有唯一性的等价物。下面的命令在确保小猫的唯一性的时候基本上会插入(如果123中的对象不存在,upsert会为你创建它)。

db.cats.update(
    { id: 123 }, 
    { $addToSet: {kittens: { $each: [ 456, 456] }}, $set: {'otherfields': 'extraval', "field2": "value2"}}, 
    { upsert: true} 
) 

将所得的物体的值将是

{ 
    "id": 123, 
    "kittens": [456], 
    "otherfields": "extraval", 
    "field2": "value2" 
} 
+0

重要的属性是:'$ addToSet'和'upsert'。 '$ set'属性与OP无关。 –

相关问题