2014-09-22 107 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大的第一要素。你将如何跟踪这次更新的变化?除非您在更新之前发布相应的查找,然后找出自己所做的更改,或者在更新之后执行查找并交叉引用结果以找出更改,否则不能执行此操作。如果应用程序是多线程的呢?除非您以某种方式协调所有线程,否则这种方法将无法工作。

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