在MongoDB中记录插入,更新和删除操作

时间:2014-09-22 18:27:58

标签: mongodb mongodb-.net-driver

我是MongoDB的新手。我正在寻找一种方法来记录插入,更新或删除文档的所有操作,以便维护更改历史记录。因此,例如,我想知道特定文档中的特定字段何时更新,更新内容以及之前的内容。这适用于使用C#MongoDB驱动程序的ASP.NET C#应用程序,因此我不介意该解决方案是仅涉及Mongo本身还是C#代码。

实施例:

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

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#添加手动Log()函数调用

实现:每次使用新操作调用MongoDB C#驱动程序API时,让程序员还添加一行调用特殊函数来处理日志文件的日志记录。

问题:依赖程序员实际记住手动添加此函数调用并正确调用它。一个简单的错误导致日志记录系统变得不可靠。

可能的解决方案4:为C#

中的API操作创建包装函数

实施:程序员不直接调用API,而是调用处理它们工作的函数。这需要大量工作,在包装器功能级别处理每种可能类型的相关API调用,但是一致且可靠。抽象数据库访问的好方法,这样就不会因为错误的低级API调用而破坏某些东西。不在DAL上工作的人可以只调用包装函数,函数会计算出详细信息,包括日志记录。

问题:开发包装函数更具挑战性,因为它需要考虑修改文档的所有可能的API调用。

现在我倾向于解决方案4.但是,如果有更简单的方法,我有兴趣听到它。

1 个答案:

答案 0 :(得分:2)

没有。从2.6开始,MongoDB中没有这样的功能。跟踪CRUD活动的标准选项是oplog和查询概要文件集合。这两个都是上限的,不足以满足您的目的。 oplog不存储文档的原始状态,只是指示如何将其设置为新状态:类似$inc的内容将在oplog条目中更改为$set。如果文档的更改时间不超过上限集合的窗口,那么下一次更改之前的状态将会丢失。分析集合用于性能监视,不存储对文档的更改,只存储已发送的查询,因此要了解查询如何影响数据库的状态,您还需要了解有关数据库状态的大量信息。查询运行时的数据库。

我不知道有任何第三方工具可以执行此操作,因此据我所知,您必须自己编写。您需要在应用程序中将其实现为一个层,并且无法跟踪对应用程序外部的MongoDB的访问。您的应用程序及其使用MongoDB的负担将很大。创建这样的东西可能是不现实的。例如,假设您的应用程序发布更新

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

这将查找t数组中至少有一个元素大于9的所有文档,然后将数组的第一个元素减小到大于9。您如何跟踪此更新的更改?除非您在更新之前发出相应的查找,然后要么弄清楚自己的更改,要么在更新后进行查找并交叉引用结果以找出更改,否则您不能这样做。如果应用程序是多线程的怎么办?除非你以某种方式协调所有线程,否则这种方法不会起作用。

使用客户端跟踪更改可能是现实的,如果您可以保持线程一次一个地访问数据库,并且您的更新非常简单,例如一次只能访问一个文档。