我是Key-Value Stores的新手,我需要你的建议。我们正在开发一个管理文档及其修订的系统。有点像维基。我们正在考虑将这些数据保存在一个关键值存储中。
请不要给我一个您喜欢的数据库的建议,因为我们想要破解它,以便我们可以使用许多不同的键值数据库。我们正在使用node.js,因此我们可以轻松使用json。
我的问题是:数据库的结构应该是什么样的?我们有每个文档的元数据(timestamp,lasttext,id,latestrevision),我们有每个版本的数据(更改,作者,时间戳等...)。那么,你推荐哪种键/值结构?
THX
答案 0 :(得分:5)
来自MongoDB的groups。它有些特定于MongoDB,但它非常通用。
这些历史实施大多分为两种常见策略。
理论上,您可以将文档的历史记录嵌入到文档本身中。这甚至可以原子地完成。
> db.docs.save( { _id : 1, text : "Original Text" } )
> var doc = db.docs.findOne()
> db.docs.update( {_id: doc._id}, { $set : { text : 'New Text' }, $push : { hist : doc.text } } )
> db.docs.find()
{ "_id" : 1, "hist" : [ "Original Text" ], "text" : "New Text" }
> db.docs.save( { _id : 1, text : "Original Text" } )
> var doc = db.docs.findOne()
> db.docs_hist.insert ( { orig_id : doc._id, ts : Math.round((new Date()).getTime() / 1000), data : doc } )
> db.docs.update( {_id:doc._id}, { $set : { text : 'New Text' } } )
在这里你会看到我做了两次写作。一个到主集合和 一个到历史收藏。 要获得快速历史记录查找,只需抓取原始ID:
> db.docs_hist.ensureIndex( { orig_id : 1, ts : 1 })
> db.docs_hist.find( { orig_id : 1 } ).sort( { ts : -1 } )
history collection
到original collection
在密钥值存储中保存包含修订的文档的最佳方法是什么?
很难说有一种“最佳方式”。显然这里有一些权衡取舍。
嵌入:
单独收集:
答案 1 :(得分:1)
我会在附加修订数据的每个文档下保留实际数据的层次结构,例如:
{
[
{
"timestamp" : "2011040711350621",
"data" : { ... the real data here .... }
},
{
"timestamp" : "2011040711350716",
"data" : { ... the real data here .... }
}
]
}
然后使用推送操作添加新版本并定期删除旧版本。您可以使用最后(或第一个)过滤器仅在任何给定时间获取最新副本。
答案 2 :(得分:1)
我认为有多种方法,这个问题已经过时了,但我会在今年早些时候的工作中给出两分钱。我一直在使用MongoDB。
在我的情况下,我有一个用户帐户,然后在不同的社交网络上有个人资料。我们希望跟踪社交网络配置文件的更改并希望修改它们,以便我们创建两个结构来测试。两种方法都有一个指向外部对象的User对象。我们不想从一开始就嵌入对象。
用户看起来像:
User {
"tags" : [Tags]
"notes" : "Notes"
"facebook_profile" : <combo_foreign_key>
"linkedin_profile" : <same as above>
}
然后,对于combo_foreign_key,我们使用了这种模式(为简单起见使用Ruby插值语法)
combo_foreign_key = "#{User.key}__#{new_profile.last_updated_at}"
facebook_profiles {
combo_foreign_key: facebook_profile
... and you keep adding your foreign objects in this pattern
}
这使我们O(1)查找用户的最新FacebookProfile,但要求我们保留最新的FK存储在User对象中。如果我们想要所有的FacebookProfiles,那么我们会在facebook_profiles集合中询问前缀为“#{User.key} __”的所有密钥,这是O(N)......
我们尝试的第二个策略是在User对象上存储这些FacebookProfile键的数组,以便User对象的结构从
更改 "facebook_profile" : <combo_foreign_key>
到
"facebook_profile" : [<combo_foreign_key>]
在我们添加新的配置文件变体时,我们只需添加新的combo_key。然后我们只是快速排序“facebook_profile”属性和最大的索引来获取我们最新的个人资料副本。此方法必须对M个字符串进行排序,然后根据该排序列表中的最大项目对FacebookProfile进行索引。获取最新版本的速度稍微慢了一些,但它让我们有机会了解每个版本的用户FacebookProfile,我们不必担心确保foreign_key真的是最新的配置文件对象。
起初我们的修订版计数非常小,而且它们都运行良好。我想我现在比第二个更喜欢第一个。
他们会非常喜欢别人对解决这个问题的看法。在另一个答案中提出的GIT想法实际上听起来非常巧妙,因为我的用例会很好用......很酷。