2015-11-23 42 views
3

我在MongoDB中有以下文檔。MongoDB數組 - 原子更新或推送元素

{ 
    "_id" : ObjectId("521aff65e4b06121b688fabc"), 
    "user" : "abc", 
    "servers" : [ 
     { 
      "name" : "server1", 
      "cpu" : 4, 
      "memory" : 4 
     }, 
     { 
      "name" : "server2", 
      "cpu" : 6, 
      "memory" : 6 
     }, 
     { 
      "name" : "server3", 
      "cpu" : 8, 
      "memory" : 8 
     } 
    ] 
} 

基於某些事件,我必須要麼更新現有服務器的CPU和內存字段或添加新的服務器陣列,如果它不數組中存在。目前,我正在分兩步執行此操作。首先檢查服務器是否已經存在於陣列中。如果是,請更新cpu和內存字段。否則,在陣列中推入一個新的子文檔。由於應用程序的多線程性質,有時會將相同的服務器多次添加到陣列。是否有任何的原子操作者執行以下兩個操作(類似於$setOnInsert操作者):

  1. 如果陣列中存在元素,更新其字段。
  2. 如果元素不存在於數組中,則推新元素。

注意:運算符$addToSet在上述情況下不起作用,因爲cpu或內存的值可能不同。

回答

0

MongoDb已經有atomic operations on individual documents。因此,就同時發送2條命令到數據庫而言,您可以直接從盒子中覆蓋。

無論如何,當這兩個命令矛盾時,就會出現您的問題。 IE如果你用同一個對象發送兩個更新,Mongo的個人文檔atmoicness不會幫助你。所以你需要做的是管理你的應用程序的多線程,這樣它就不會發送可能衝突的多個Mongo命令。

+0

謝謝。我已經做了類似於你的建議。現在,應用程序確保相同服務器的兩個更新由相同的線程處理。 –

+0

如果您的多實例部署是常見情況,這並不能解決問題。 – alexey

2

我認爲你可以使用findAndModify()來做到這一點,因爲它提供了原子更新。 但是你的文檔結構不合適。 如果您可以將您的文檔改變這個(即SERVERID成爲數組的鍵):

{ 
    "_id" : ObjectId("521aff65e4b06121b688fabc"), 
    "user" : "abc", 
    "servers" : { 
     "server1" : { 
      "cpu" : 4, 
      "memory" : 4 
     }, 
     "server2" : { 
      "cpu" : 6, 
      "memory" : 6 
     }, 
     "server3" : { 
      "cpu" : 8, 
      "memory" : 8 
     }, 
    } 
} 

然後你可以使用一個原子命令findAndModify()更新,而不需要使用兩個單獨的發現的()更新()

db.collection.findAndModify 
(
{query: 
    {"_id" : ObjectId("521aff65e4b06121b688fabc")}, 
    update: 
    {$set: {"servers.server4": {"cpu":5, "memory":5 }}}, 
    new: true} 
) 

當使用這個,如果servers.server4不存在,它會被插入,否則更新。

+0

謝謝。該模式將簡化數據插入。但是,這會使提取查詢複雜化。該應用程序的主要要求之一是使用cpu和內存列列出服務器。它們還支持篩選和排序(例如,列出所有服務器的CPU> 4)。目前,我正在使用$ unwind(聚合)列出服務器的數組。 –