2014-09-22 106 views
1

我是MongoDB的新手。我正在尋找一種方法來記錄所有插入,更新或刪除文檔的操作,以便維護更改歷史記錄。因此,例如,我想知道特定文檔中的特定字段何時更新,更新的內容以及之前的內容。這適用於使用C#MongoDB驅動程序的ASP.NET C#應用程序,因此我不介意該解決方案是否涉及Mongo本身或C#代碼。在MongoDB中記錄插入,更新和刪除操作

例如:

ID |Timestamp |Operation|ObjectID |   PrevValue   |   NewValue 
----------------------------------------------------------------------------------------------- 
2153|1411390359| i |245245...|   null    |{name: "John Smith", age: 35} 
2154|1411390471| u |245245...|   {age: 35}   |   {age: 36} 
2155|1411390478| d |245245...|{name: "John Smith", age: 36}|   null 

它不必遵循這種確切的格式,但它應該可以很容易地跟蹤歷史。

我看了一下MongoDB oplog,但它看起來不太適合這種工作。例如,爲了識別對文檔的更改,它看起來像我必須查找兩個條目(文檔的最新更新條目和先前的文檔條目,可能是更新或插入),然後比較每個字段在文件中檢查哪個(哪些)被改變了,他們的原始值是什麼。爲了提高效率,我寧願僅僅擁有一個包含所有這些信息的條目,以防需要許多查詢來檢查對許多文檔的更改。我想確保使用日誌儘可能無痛苦。如果日誌存儲在MongoDB集合中,每個條目的文檔(如oplog)使查詢變得容易,這也是理想的選擇。

在MongoDB(oplog除外)中是否有一個功能可以完成這樣的事情?如果沒有,是否有一個好的第三方工具可以?或者我必須手動實現它?

編輯:一些更多的細節:

1)OPLOG的另一個問題是封頂的,所以一旦它運行的空間,它會刪除最早的條目。我想保留一份全部歷史的列表,不管它多大。

2)日誌的內容將以某種方式顯示給用戶,用戶可能會請求查看更改的歷史記錄。這不僅適用於數據庫管理員的內部記錄,因此需要根據需要進行查詢。

編輯#2:我一直在頭腦風暴這個問題的一些解決方案,但他們都仍然有一些缺陷,所以我希望進一步的投入,如果有人有一個更好的主意。

可能的解決方案1:爲每個版本(使用版本#)和標記(如果它已被刪除)保留一個單獨的文檔。

實現:爲每個文檔添加一個「版本」字段。版本1是初始狀態(表示插入),後續版本表示更新,這些更新放置在單獨的新創建的文檔中,而不是更新舊版本。版本-1意味着文檔現在被視爲「已刪除」。顯然這不涉及實際的日誌文件。

問題:如果我需要一次加載多個文檔的歷史更改數據,則需要大量空間和成本進行查詢。也很難確定哪些特定的字段發生了變化,除非我還包含前一版本的「更改」字段,這也增加了更多空間。如果舊版本也需要搜索,也可能會使用最新版本進行查詢時會變得麻煩和昂貴(無法確定哪個版本是當前版本)。即使有另一面旗幟說它是最新的,我仍然需要確保旗幟隨時根據需要進行更新。

可能的解決方案2:維護修訂歷史爲每個文檔的子文檔場

實現:每個文件都有一個包含有一個版本號每個修訂了「RevisionHistory」字段。更容易查找單個文檔的歷史數據

問題:由於新字段的原因,跨多個文檔執行歷史記錄查詢的難度加大,並且執行更新的API調用更加複雜。特別是,我需要在過去X小時內(X由用戶提供)顯示所有更改,作爲實施的一部分,如果使用此方法,則需要掃描所有文檔。

可能的解決方案3:添加手動日誌()函數調用從C#

實現:每次MongoDB的C#驅動程序的API調用一個新的操作,有程序員還添加一行調用一個特殊的函數來處理日誌文件的記錄。

問題:取決於程序員實際記住手動添加此函數調用並正確調用它。一個簡單的錯誤會導致日誌系統變得不可靠。

可能的解決方案4:創建一個從C#

執行情況的API操作的包裝函數:程序員不直接調用API,但調用處理的工作爲他們的功能。這需要很多工作,在包裝函數級別處理每種可能的相關API調用類型,但是一致且可靠。抽象出DB訪問的好方法,以便在錯誤的低級別API調用中不會出現問題。有些不在DAL上工作的人可以調用包裝函數,函數會計算出詳細信息,包括日誌記錄。

問題:開發包裝函數更具挑戰性,因爲它需要考慮修改文檔的所有可能的API調用。

現在我傾向於解決方案4.但是,如果有更簡單的方法來做到這一點,我有興趣聽到它。

回答

2

不,從2.6開始,MongoDB中沒有這樣的功能。跟蹤CRUD活動的標準選項是oplog和查詢配置文件集合。這些都是封頂的,不足以達到你的目的。 oplog不存儲文檔的原始狀態,只是說明如何將其設置爲新狀態:類似$inc將在oplog條目中更改爲$set。如果文檔長度不超過封頂集合的窗口時間,那麼下一次更改之前的狀態將丟失。分析集合用於性能監視,不會存儲對文檔的更改,僅存儲發送的查詢,因此要知道查詢如何影響數據庫的狀態,還需要了解有關數據庫狀態的很多信息查詢運行的時間。

我不知道有任何第三方工具可以做到這一點,所以據我所知你必須自己寫。您將需要在應用程序中將它實現爲一個層,並且不會跟蹤應用程序外部對MongoDB的訪問。你的應用程序的負擔和它對MongoDB的使用將會很大。創建這樣的東西可能是不現實的。例如,假設您的應用程序發出的更新

> db.collection.update({ "t" : { "$gte" : 10 } }, { "$inc" : { "t.$" : -1 } }) 

此發現的所有文件,其中t陣列中的至少一個元素比9大,然後遞減陣列比9大的第一要素。你將如何跟蹤這次更新的變化?除非您在更新之前發佈相應的查找,然後找出自己所做的更改,或者在更新之後執行查找並交叉引用結果以找出更改,否則不能執行此操作。如果應用程序是多線程的呢?除非您以某種方式協調所有線程,否則這種方法將無法工作。

如果您可以讓您的線程一次訪問數據庫並且您的更新非常簡單,例如一次只打一個文檔,那麼使用客戶端跟蹤更改可能是現實的。