假设我的CouchDB数据库中存储了两种类型的文档。首先是将属性类型设置为联系,然后将其设置为电话。联系人类型文档有另一个名为name的属性。电话类型具有属性编号和contact_id,以便它可以引用联系人。这是一个简单的一对多方案,其中一个联系人可以有N个电话号码(我知道它们可以嵌入单个联系人文档中,但我需要证明与不同文档的一对多关系)。
原始示例数据,Scott有2个电话号码,Matt有1个号码:
{_id: "fc93f785e6bd8c44f14468828b001109", _rev: "1-fdc8d121351b0f5c6d7e288399c7a5b6", type: "phone", number: "123456", contact_id: "fc93f785e6bd8c44f14468828b00099f"}
{_id: "fc93f785e6bd8c44f14468828b000f6a", _rev: "1-b2dd90295693dc395019deec7cbf89c7", type: "phone", number: "465789", contact_id: "fc93f785e6bd8c44f14468828b00099f"}
{_id: "fc93f785e6bd8c44f14468828b00099f", _rev: "1-bd643a6b0e90c997a42d8c04c5c06af6", type: "contact", name: "Scott"}
{_id: "16309fcd03475b9a2924c61d690018e3", _rev: "1-723b7c999111b116c353a4fdab11ddc0", type: "contact", name: "Matt"}
{_id: "16309fcd03475b9a2924c61d69000aef", _rev: "3-67193f1bfa8ed21c68e3d35847e9060a", type: "phone", number: "789456", contact_id: "16309fcd03475b9a2924c61d690018e3"}
地图功能:
function(doc) {
if (doc.type == "contact") {
emit([doc._id, 1], doc);
} else if (doc.type == "phone") {
emit([doc.contact_id, 0], doc);
}
}
减少功能:
function(keys, values) {
var output = {};
for(var elem in values) {
if(values[elem].type == "contact") {
output = {
"ID": values[elem]._id,
"Name": values[elem].name,
"Type": values[elem].type,
"Phones": []
};
} else if (values[elem].type == "phone") {
output.Phones.push({
"Number": values[elem].number,
"Type": values[elem].type
});
}
}
return output;
}
由于Map函数中的键,group_level设置为1。现在我可以通过附带的手机获取我的联系人,例如:
http://localhost:5984/testdb2/_design/testview/_view/tv1?group_level=1
或者像这样搜索与startkey和endkey的某些联系:
http://localhost:5984/testdb2/_design/testview/_view/tv1?group_level=1&startkey=[%22fc93f785e6bd8c44f14468828b00099f%22]&endkey=[%22fc93f785e6bd8c44f14468828b00099f%22,{}]
结果看起来我想要的方式 - 联系人将根据一对多的关系嵌入手机。这就是问题:这是如何在CouchDB中使用MapReduce函数的正确方法吗?使用这种方法时是否存在显着的性能问题?
答案 0 :(得分:7)
一般来说,如果不emit(...,doc)
,则使用较少的磁盘空间。
您可能想要重新考虑使用reduce功能。实际上没有必要获得您需要的数据。例如,如果您拥有大量记录,则以下内容可能会占用较少的磁盘空间并且性能会更好。
此外,我认为在减少功能中构建比文档包含的数据更多的CouchDB。在这种情况下你不是那样做的,但是你遵循的模式可能会导致你以后遇到麻烦。它被称为减少是有原因的。 : - )
所以类似这样的东西更像是CouchDB:
function(doc) {
if (doc.type == "contact") {
emit([doc._id, 0], {
"Name": doc.name,
"Type": doc.type
});
} else if (doc.type == "phone") {
emit([doc.contact_id, 1], {
"Number": doc.number,
"Type": doc.type
});
}
}
查询特定联系人,如下所示:
http://localhost:5984/testdb2/_design/testview/_view/tv1? startkey=[%22fc93f785e6bd8c44f14468828b00099f%22, 0] &endkey=[%22fc93f785e6bd8c44f14468828b00099f%22,1]
当然,你没有得到与以前相同的JSON结构的结果,但我相信这在CouchDB中表现更好。
答案 1 :(得分:0)
这个答案完全是假冒和轶事,但这正是我在CouchDB中与一对多关系的合作方式。如果有任何缩放问题,我还没有看到它们。 (但我承认我没有太努力找到它们。)
虽然,在你的地图功能中,你为什么要把你的电话分类到联系人(1)之前的第一个(0)?您的reduce函数需要相反的顺序。