2015-08-09 59 views
1

我有這樣一個集合:如何在mongodb中創建兩個交換字段?

{ 'start_location': '1', 'end_location': '2' }, 
{ 'start_location': '3', 'end_location': '4' } 

我想確保以下條目無法插入:

{ 'start_location': '1', 'end_location': '2' } 

{ 'start_location': '2', 'end_location': '1' } 

雖然這樣的條目應被允許:

{ 'start_location': '1', 'end_location': '3' } 

我試過做複合索引但不能成功。

+0

我不認爲這是可能的。 – Philipp

回答

0

索引不能執行這樣的邏輯對你,但你可以在邏輯構建,使創建只可能在配對組合存在。爲了做到這一點,你需要使用"upsert"功能,只有把你的修改一個$setOnInsert

db.startend.update(
    { 
     "$or": [ 
      { "start_location": "2", "end_location": "1" }, 
      { "start_location": "1", "end_location": "2" } 
     ] 
    }, 
    { 

     "$setOnInsert": { 
      "start_location": "2", 
      "end_location": "1" 
     } 
    }, 
    { "upsert": true } 
) 

內將匹配文檔與"start_location": "1""end_location": "2",因此不創建一個新文檔。但是,如果組合不存在:

db.startend.update(
    { 
     "$or": [ 
      { "start_location": "1", "end_location": "3" }, 
      { "start_location": "3", "end_location": "1" } 
     ] 
    }, 
    { 

     "$setOnInsert": { 
      "start_location": "1", 
      "end_location": "3" 
     } 
    }, 
    { "upsert": true } 
) 

然後創建一個新文檔。

因此,$or條件允許您以參數的相反順序以及您想要的順序來指定組合,以便您可以比較每個可能的匹配項。

下,當條件不具備,或者你可以把你可能想使$setOnInsert塊外,如該$inc對每場比賽,其中增加值的任何修改的新文件被創建一個「更新插入」你刻意要做到這一點:

db.startend.update(
    { 
     "$or": [ 
      { "start_location": "2", "end_location": "1" }, 
      { "start_location": "1", "end_location": "2" } 
     ] 
    }, 
    { 

     "$setOnInsert": { 
      "start_location": "2", 
      "end_location": "1" 
     }, 
     "$inc": { "counter": 1 } 
    }, 
    { "upsert": true } 
) 

那麼作爲說明,指標是不執行這個邏輯的方式,但指定的「前進」,「反轉」條件中的語句是一個相對容易的模式可供遵循和實施「插入/更新」。


作爲警告的話,在此做一點更多的研究可能會導致您使用「開始」和「結束」兩個數組位置這樣一個需要考慮的陣列格式:

{ "location": [ "1", "2" ] }, 
{ "location": [ "3", "4" ] } 

你可能認爲這是一個好主意,因爲有一個$all運算符,在這裏可以用來在「所有」元素存在的「任何順序」中基本匹配。但是有一個「隱藏的捕獲」在這裏,這實際上將失敗,出現錯誤:

db.startend.update(
    { 
     "location": { "$all": [ "1", "3" ] } 
    }, 
    { 
     "$setOnInsert": { 
      "location": [ "1", "3" ] 
     } 
    }, 
    { "upsert": true } 
) 

而且誤差將是:

WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0, "writeError" : { "code" : 54, "errmsg" : "cannot infer query fields to set, path 'location' is matched twice" } })

在那裏你會有理由期待一個「UPSERT」將發生在這裏,而是產生錯誤。這裏的具體問題是因爲被比較的數據是在一個數組中,更新是「試圖」確定要更新數組的哪個「位置」,儘管這不是你在這裏要求的。

爲了解決這個問題,你需要強制查詢引擎「不」嘗試匹配數組的位置,唯一的辦法就是用JavaScript評估,以取代邏輯什麼$all是做對數組的對比:

db.startend.update(
    { 
     "$where": function() { 
      var input = [ "1", "3" ]; 

      return this.location.every(function(el) { 
       return (input.indexOf(el) != -1); 
      }); 
     } 
    }, 
    { 
     "$setOnInsert": { 
      "location": [ "1", "3" ] 
     } 
    }, 
    { "upsert": true } 
) 

雖然這種邏輯將正確把握,它是不是真的希望和$where條件在這裏不能使用查找索引,這意味着表達式必須始終掃描每個文檔在集合中以確定哪​​裏存在或不存在匹配。

因此,需要注意的是,表面上看起來很不錯的東西,並且會在編碼過程中花費一些複雜性,實際上最終會成爲一個巨大的性能問題。

相關問題