Javascript CouchDB视图从两个单独的文档中使用嵌入数组组合JSON对象

Javascript CouchDB视图从两个单独的文档中使用嵌入数组组合JSON对象,javascript,json,couchdb,mapreduce,Javascript,Json,Couchdb,Mapreduce,假设我的CouchDB数据库中存储了两种类型的文档。第一个属性类型设置为联系人,第二个属性类型设置为电话。联系人类型文档具有另一个名为name的属性。电话类型具有属性号和联系人id,以便可以引用联系人。这是一个简单的一对多场景,其中一个联系人可以有N个电话号码(我知道它们可以嵌入到单个联系人文档中,但我需要演示与不同文档的一对多关系) 斯科特有2个电话号码,马特有1个电话号码的原始示例数据: {_id: "fc93f785e6bd8c44f14468828b001109", _rev: "1-f

假设我的CouchDB数据库中存储了两种类型的文档。第一个属性类型设置为联系人,第二个属性类型设置为电话。联系人类型文档具有另一个名为name的属性。电话类型具有属性号和联系人id,以便可以引用联系人。这是一个简单的一对多场景,其中一个联系人可以有N个电话号码(我知道它们可以嵌入到单个联系人文档中,但我需要演示与不同文档的一对多关系)

斯科特有2个电话号码,马特有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;
}
减少功能:

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_级别设置为1。现在,我可以使用附带的手机获取联系人,例如:

http://localhost:5984/testdb2/_design/testview/_view/tv1?group_level=1
http://localhost:5984/testdb2/_design/testview/_view/tv1?group_level=1&startkey=[%22fc93f785e6bd8c44f14468828b00099f%22]&endkey=[%22fc93f785e6bd8c44f14468828b00099f%22,{}]
或者像这样搜索startkey和endkey的联系人:

http://localhost:5984/testdb2/_design/testview/_view/tv1?group_level=1
http://localhost:5984/testdb2/_design/testview/_view/tv1?group_level=1&startkey=[%22fc93f785e6bd8c44f14468828b00099f%22]&endkey=[%22fc93f785e6bd8c44f14468828b00099f%22,{}]

结果完全符合我的要求——联系人将根据一对多的关系配备嵌入式手机。问题是:这是在CouchDB中使用MapReduce函数的正确方法吗?使用这种方法时是否存在显著的性能问题?

这个答案完全是虚构的,而且是轶事,但这正是我在CouchDB中处理一对多关系的方式。如果有任何缩放问题,我还没有看到。(但我承认我没有太努力去寻找它们。)


尽管如此,在地图功能中,为什么要将手机排序为联系人(1)之前的第一个(0)?reduce函数需要相反的顺序

一般来说,如果不
emit(…,doc)
,则使用的磁盘空间更少

您可能需要重新考虑使用reduce函数。实际上,没有必要获取所需的数据。例如,如果您有大量记录,那么符合以下内容的内容可能会占用更少的磁盘空间,并且性能更好

另外,我认为在reduce函数中构建比文档包含的数据更多的数据是违反CouchDB规则的。在本例中,您没有这样做,但您遵循的模式可能会在以后导致麻烦。它被称为reduce是有原因的。:-)

所以像这样的东西更像是CouchDB的方式:
功能(doc){
如果(单据类型==“联系人”){
发出([doc.\u id,0]{
“名称”:文件名,
“类型”:单据类型
});
}else if(doc.type==“电话”){
发出([doc.contact_id,1]{
“编号”:文件编号,
“类型”:单据类型
});
}
}

查询特定联系人,如下所示:

http://localhost:5984/testdb2/_design/testview/_view/tv1? startkey=[%22fc93f785e6bd8c44f14468828b00099f%22, 0] &endkey=[%22fc93f785e6bd8c44f14468828b00099f%22,1] http://localhost:5984/testdb2/_design/testview/_view/tv1? startkey=[%22fc93f785e6bd8c44f14468828b00099f%22,0] &endkey=[%22fc93f785e6bd8c44f4468828b00099f%22,1]
诚然,您不会在与以前相同的JSON结构中获得结果,但我相信这在CouchDB中表现得更好。

它是这样排序的,因为当我直接通过浏览器访问视图时,我必须在url中插入descending=true。