2012-04-30 23 views
17

在我的scenerio中,作者在一個集合中,每個作者有messages,作者的每條消息可以有events。每個演員只允許執行一次動作。如何確保基於特定字段的數組中的唯一項 - mongoDB?

db.people.ensureIndex({messages.messageEvents.eventName: 1, messages.messageEvents.actorId: 1}, {unique: true}); 

我添加了索引但它沒有效果。正如你在下面看到的,我的文檔有三個元素,其中"eventName":"vote""actorId":"1234"應該違揹我的約束。

如何確保messageEvents數組基於eventNameactorId字段的唯一項?

其實,我需要更新現有的項目,而無需第二次搜索和更新事件,而不是拒絕它。

{ 
    "_id": "1234567", 
    "authorPoint": 0, 
    "messages": [ 
    { 
     "messageId": "112", 
     "messageType": "Q", 
     "messagePoint": 0, 
     "messageEvents": [ 
     { 
      "eventName": "Add", 
      "actorId": "1234", 
      "detail": "" 
     }, 
     { 
      "eventName": "Vote", 
      "actorId": "1234", 
      "detail": "up" 
     }, 
     { 
      "eventName": "Vote", 
      "actorId": "1234", 
      "detail": "down" 
     }, 
     { 
      "eventName": "Vote", 
      "actorId": "1234", 
      "detail": "cork" 
     } 
     ] 
    } 
    ] 
} 

回答

19

Mustafa,唯一的約束不會在單個數組內強制執行,儘管它們在集合中的文檔之間執行。這是一個已知的bug不會被固定了一會兒:

https://jira.mongodb.org/browse/SERVER-1068

有一個變通方法,雖然。保持您的唯一索引到位,並且:

1)確保您的應用程序不會在數組中插入具有重複值的新文檔。插入前您可以檢查應用程序代碼中的唯一性。

2)更新現有文檔時,使用$ addToSet而不是$ push。

+0

感謝您的回答。你是對的。經過幾次研究,我已經更改了我的文檔表示並應用瞭解決方法。我希望有簡單的方法。它具有代價並且可能導致代碼複雜度:( – yuceel

+1

即使使用$ addToSet,也可以說我們推送了一些內容作爲 {userId:1234,vote:obama},$ addToSet不會停止 {userId:1234,vote:romney },你如何確保對象集只在userId上強制唯一? –

+0

@OuwenHuang我認爲這是一個單獨的問題,我會單獨詢問它,而不是評論這個接受的答案。 –

相關問題