2016-08-02 427 views
0

我有一個應用程序不斷地將文檔插入到MongoDB集合中。MongoDB - 反映插入順序的字段

我正在尋找一種方法來查詢其插入順序後的文檔。

候選人我想用:

  • _id
  • 創建日期域
  • 序列號(自動遞增)

_id領域是不是一個好候選人作爲文檔說。創建日期字段可能是一個很好的候選字段,但時鐘可能不同步的事實可能會破壞訂單。關於序列號,文件提出了兩種方法:計數器和樂觀循環。由於文檔D1可能會插入另一個文檔D2,即使D1.seq < D2.seq,計數器方法也不能保證插入順序。例如,如果D1獲取序列號5,則D2獲取序列號6,然後插入D2,然後插入D1。樂觀循環的方法是瘋狂的情況下,沉重的插入環境。

有沒有另一種方法?


編輯:

使用計數器的方法是有問題的。考慮以下情況。我有一個應用程序A,它不斷地將文檔插入到一個集合中。我還有另一個應用程序B,它不斷地輪詢來自同一個集合的文檔。應用程序A是多線程的。兩個線程T1T2分別將插入文檔D1D2。在插入過程中,應用程序B要求提供更多文檔。假設以下的操作順序:

  1. 主題A-T1抓住下一個序列號N
  2. 主題A-T2抓住下一個序列號N+1
  3. 主題A-T2插入D2
  4. 應用B詢問與seq >= N文件(假設最後處理的文件有seq號N-1)並且收到D2D1還沒有恩插入尚)
  5. 主題A-T1插入D1
  6. 應用B詢問與seq >= N+2文件(自上次處理的文檔具有序列號N+1

在這種情況下,D1將永遠不會被處理。

+0

如果我正確地理解了你,你需要一種方式來知道文件創建和保存的順序。我建議你自己生成_id。例如,當服務器啓動時,你插入最後一個_id(或最大的一個,就像1505)。然後你只需在每個文件上增加計數器。你很好走。即使某些文檔無法保存,您可以將其保存到某個JSON文件並稍後重新保存。當時會生成_id,您將擁有訂單系統。希望這可以幫助。 –

+0

我不明白你的方法與問題中的第三種方法不同。 –

+0

是的,這裏只有更多的單詞。 –

回答

0

如果您希望每秒插入數十次,樂觀鎖定是唯一的方法。

否則時鐘同步可能是一個更好的主意。

考慮到櫃檯,你能否詳細說明它是如何影響你的申請的,如果D1D2之後持續存在,你是否保證獲得順序號碼的順序? MongoDB本身的「插入」操作有多個階段,您可以儘可能深入地依賴日誌記錄。

編輯

你可以考慮tailable cursor作爲應用B一個選擇嗎?它不直接回答這個問題,但它可能解決問題背後的問題。

EDIT 2

,那麼你可能需要使用任何種類的消息隊列的應用程序之間進行通信,就像在圖像上。這可能是一種矯枉過正,但如果你確信樂觀鎖定是一個瓶頸,那麼它可能是可以接受的。

在下面的圖片:

  1. 應用A以任意順序插入文檔和檢索蒙戈客戶端唯一對象ID。

  2. 應用A發送的objectID隊列以任意順序

  3. 應用B獲取下一步的objectID從隊列

  4. 應用通過ID從數據庫B取文件

enter image description here

編輯3

最後,你可以考慮到狀態添加到文檔和樂觀鎖轉移到應用B

  1. 檢索和未處理的文件的objectID:db.collection.findOne({status: null}, {})

  2. 將其狀態更改爲'處理'

    db.collection.findAndModify({ 
        query: { _id: objectId, status: null }, 
        update: { $set: { status: 'processing' }} 
    }) 
    

    ,如果返回null - 該文件正在由B另一個實例處理,所以返回步驟1

  3. 過程中的文檔並更新其狀態爲「完成」:

    db.collection.findAndModify({ 
        query: { _id: objectId, status: 'processing' }, 
        update: { $set: { status: 'done' }} 
    }) 
    

使用這種方法,你完全不關心確切的序列。如果您想按順序處理文檔,您可以添加時間戳或在ObjectId上繼續對第1步中的文檔進行排序。當然,這可能不是確切的順序,但您不需要它來保證處理所有文檔。

+0

請參閱我的編輯 –

+0

關於您對樂觀循環的評論,我認爲它是相反的 - 即樂觀循環效率低下,併發插入很多,因爲它可能會循環多次,才能插入文檔而不會出現重複錯誤。 –

+0

樂觀鎖vs時間戳的原因是,當你以毫秒爲單位計算時,NTP可能不夠,但我看到你指向執行。儘量避免過早優化,直到你**證明**這是一個問題。 關於您的編輯 - 應用程序「B」如何知道序列號?它完全屬於應用程序'A'域。 'B'只能要求返回最新的1000個文件,按序號排序。像「比時間戳更早」的任何其他過濾器也可以,假設您爲過濾添加了時間戳。序列號僅用於排序。 –