Python + MongoDB 文档版本控制
我正在开发一个应用程序,主要用于公司内部的项目和任务跟踪。目前我在玩MongoDB(一个数据库)。我心里有一个大概的结构设计:
task
_id
name
project
initial_notes
versions
number
versions
version_1
worker
status
date(if submitted)
review_notes(if rejected)
reply_on(if accepted/rejected)
(version_n)(if any)
我遇到的问题是如何管理任务的版本。我看了很多可能的方法,但总是理解得不够透彻。我看到了一些我喜欢的内容,在这里,我很喜欢mongoid的版本管理方式。
经过进一步思考,我更希望它能像这样:
task
_id
versions
number_of_versions: 3
current_version
version_no: 3
worker: bob
status: accepted
old_versions
version
version_no: 2
worker: bob
我想在显示任务列表时只展示最新版本,而在查看某个特定任务的详细信息页面时,想要显示该任务的所有版本。这样的结构可行吗?如果可以的话,我需要哪些查询来实现我的需求呢?
感谢你花时间阅读这个问题,也许还能给我一些解答。
状态:拒绝 版本 版本号:1 工作人员:smith 状态:拒绝3 个回答
我之前也遇到过同样的问题,所以我创建了一个叫做HistoricalCollection的工具:
https://pypi.org/project/historical-collection/
这个工具的使用方式和普通的集合差不多,但多了一些额外的方法:
patch_one()
- 用来更新一个项目patch_many()
- 用来批量更新多个项目find_revisions()
- 用来查找历史版本latest()
- 用来获取最新的版本
下面是一个使用的例子:
from historical_collection.historical import HistoricalCollection
from pymongo import MongoClient
class Users(HistoricalCollection):
PK_FIELDS = ['username', ] # <<= This is the only requirement
# ...
users = Users(database=db)
users.patch_one({"username": "darth_later", "email": "darthlater@example.com"})
users.patch_one({"username": "darth_later", "email": "darthlater@example.com", "laser_sword_color": "red"})
list(users.revisions({"username": "darth_later"}))
# [{'_id': ObjectId('5d98c3385d8edadaf0bb845b'),
# 'username': 'darth_later',
# 'email': 'darthlater@example.com',
# '_revision_metadata': None},
# {'_id': ObjectId('5d98c3385d8edadaf0bb845b'),
# 'username': 'darth_later',
# 'email': 'darthlater@example.com',
# '_revision_metadata': None,
# 'laser_sword_color': 'red'}]
你也可以考虑这样一个模型:
task
_id
...
old_versions [
{
retired_on
retired_by
...
}
]
这个模型的好处是,你当前的数据总是在最上层(你不需要明确地跟踪当前版本,因为文档本身就是当前版本),而且你可以通过获取当前版本,去掉 old_versions
字段,然后把它加到数据库的 old_versions
字段中,轻松地追踪历史记录。
因为你似乎想要减少网络的输入输出,这样做也能让你在不需要旧版本时,轻松避免加载 old_versions
:
> db.tasks.find({...}, {old_versions: 0})
你还可以更复杂一点,只存储那些已经改变的字段的旧版本列表。这需要在你的应用层写更精细的代码,如果你不预期会有很多次修改或者这些文档不会很大,可能就没必要这么做。
当然可以,为什么不呢?这个方案是可行的。另外,你有没有考虑过这样的做法:
task
...
versions = [ # MongoDB array
{ version_id
worker
status
date(if submitted)
review_notes(if rejected)
reply_on(if accepted/rejected)
},
{ version_id : ... },
...
这是一个可能的版本插入查询:
tasks.update( { # a query to locate a particular task},
{ '$push' : { 'versions', { # new version } } } )
请注意,在这种情况下,从版本数组中获取最后一个版本是由程序来完成的,而不是由Mongo数据库来处理的。