我开始研究map-reduce数据库。如何在map-reduce数据库中实现引用,例如CouchDB或MongoDB?例如,假设我有司机和汽车,我想标记一些司机驾驶汽车。在SQL中它类似于:
SELECT person_id, car_id FROM driver, car WHERE driver.car = car.car_id
(也就是说,如果我的记忆正确 - 我还没有在SQL中编程一段时间。)
在具有引用的语言中,它更简单:Person的实例可以指向Car的实例。
map-reduce与这种关系相当的是什么?
答案 0 :(得分:2)
在CouchDB中,您可以编写一个map / reduce,用复杂的键输出所有汽车和驱动程序,然后使用键范围来选择两者。例如,假设您的文档看起来像这两个......
{
"_id": "...",
"_rev": "...",
"docType": "driver"
}
{
"_id": "...",
"_rev": "...",
"docType": "car",
"driver": "driver's _id"
}
您可以使用duck typing而不是指定docType,但我更喜欢这种方法。
你的地图功能:
function(doc)
{
if(doc.docType == "driver")
emit([doc.id, 0], doc);
elseif(doc.docType == "car")
emit([doc.driver, 1], doc];
}
我们的复杂键是一个数组,第一项始终是驱动程序的_id。数组中的第二项防止键冲突,并允许我们直接引用汽车或驱动程序(稍后将详细介绍)。
我们现在可以使用键范围查询参数来获取两个文档。
?startkey=["driver _id"]&endkey=["driver _id", {}]
这基本上说“给我任何带有驱动程序_id作为第一项的数组,以及第二项中的任何数据。这是有效的,因为对象 - endkey
数组中的第二项 - 被排序为最高。有关如何在密钥中对项目进行排序/加权的详细信息,请参阅http://wiki.apache.org/couchdb/View_collation?redirect=ViewCollation#Collation_Specification。
这也可以很好地扩展,因为我们可以在我们的map函数中添加更多信息,而无需在客户端中更改我们的查询。假设我们添加了一个赞助商docType:我们只为docType字段添加另一个elseif
,然后添加emit([doc.driver, 2], doc);
。现在,我们可以使用上面相同的键范围查询在一个请求中提取所有三个文档。
当然,您也可以指定单个文档而不是全部文档。 ?key=["driver's _id", 1]
只会为指定的驱动程序提取汽车。
干杯。
答案 1 :(得分:1)
在文档数据库中,您可以将相关对象嵌入到拥有对象的文档中,例如驱动程序文档还包含属于该驱动程序的所有汽车。这就是文档数据库的力量;它们允许您轻松存储非规范化数据。
{
"_id": "joe_the_driver",
"name": "Joe",
"cars": [
{ "_id": "123-AB", /* car properties */ },
{ "_id": "456-YZ", /* car properties */ }
]
}
此格式仅适用于一对多关系。如果驾驶员和汽车之间的关系是多对多的,那么您将不得不创建查找文档:
{
"_id": "joe_the_driver",
"car_ids": [ /* ID's that refer to car documents */ ]
}
{
"_id": "123-AB",
"driver_ids": [ /* ID's that refer to driver documents */ ]
}
值得注意的是,大多数文档数据库无法以SQL数据库的方式强制执行文档之间的关系。您的应用程序负责执行和维护这些关系。