2011-07-19 52 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無關。 –

相關問題