我正在尝试在CouchDB中建立一个相当简单的关系的模型,但是我无法确定实现此目标的最佳方法。我希望用户能够创建视频游戏对象列表。我已经用"type":"game"
将视频游戏文档存储在DB中。我希望能够(通过视图)查询列表对象的ID,并获取列表的元数据(标题,创建日期等)和游戏文档的某些部分(如标题和发行日期)。此外,我希望能够将游戏添加到列表中/从列表中删除游戏,而无需下载整个列表文档并将其发布回去(因此,我不能简单地将游戏信息存储在列表文档中)最终希望支持对同一列表做出贡献的多个用户,并且我不想引入冲突。
阅读了EntityRelationships上的CouchDB Wiki之后,我确定设置关系文档可能是最好的解决方案。
{
"_id": "2600emu",
"type": "game"
}
{
"_id": 123,
"title": "Emulators",
"user_id": "dstaley",
"type": "list"
}
{
"_id": "98765456789876543",
"type": "relationship",
"list_id": 123,
"game_id": "2600emu"
}
但是,据我了解,这不允许我在一个请求中获取列表的元数据和游戏的元数据。有什么建议吗?
很好的问题。您指出了一些非常重要的原因,即使用“规范化”数据模型(带有链接的不同文档类型)是最佳模型的原因:
您也很对,这里的解决方案是'map-side-join'(从hadoop社区借来的)。基本上,您想在地图输出中使用不同的行来表示不同的信息。然后,您可以使用范围查询(开始键/结束键)仅查询所需地图结果的一部分,并查询“联接”表的实例化视图。但是,您在文档中找不到的难题之一是:
3.2.3。 Joins With Views
3.2.3.1。链接文件
[如果您的地图函数发出一个具有
{'_id': XXX}
的对象值,并且您使用include_docs=true
参数查询视图,则CouchDB将获取ID为XXX
的文档,而不是经过处理以发出键/值对的文档。
全部说明。这样,您便可以通过外键解除对指向已存储链接文档的指针的引用。然后,您可以使用复合键(是JS数组的键)和view collation rules来结合使用。
以便您的视图行的排序方式如下:
["list_1"], null ["list_1", "game"], {"_id":"game_1234"} ["list_1", "game"], {"_id":"game_5678"} ["list_2"], null ["list_2","game"], {"_id":"game1234"} ["list_3"], null ...
将其与您现有的数据模型放在一起,下面是一些(未经测试的)伪代码应该可以解决的问题:
function(doc) { if (doc.type=="list") { //this is the one in the one-to-many emit( [doc._id]),); } else if (doc.type=="relationship") { //this is the many in the one-to-many //doc.list_id is our foreign key to the list. We use that as the key //doc.game_id is the foreign key to the game. We use that as the value emit( [doc.list_id,'game'], {'_id': doc.game_id}); } }
最后,您将使用startkey / endkey进行查询,以便获得所有您感兴趣的以list_id开头的行。它看起来像是:
curl -g 'https://usr:[email protected]/db/_design/design_doc_name/_view/view_name?startkey=["123"]&endkey=["123",{}]&include_docs=true'
-g
选项告诉curl不要泛滥,这意味着您不必取消引用方括号等,并且include_docs=true
选项将跟随指针指向您在game_id
中指定的外键relationship
文档。
分析: