代码之家  ›  专栏  ›  技术社区  ›  yojimbo87 jesuisbonbon

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

  •  5
  • yojimbo87 jesuisbonbon  · 技术社区  · 14 年前

    假设在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;
    }
    

    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,{}]
    

    2 回复  |  直到 14 年前
        1
  •  7
  •   BenD    14 年前

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

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

    所以像这样的东西更像是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中执行得更好。

        2
  •  0
  •   Rick O    14 年前

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

    不过,在地图功能中,为什么要将手机排序为在联系人(1)之前先显示(0)?reduce函数需要相反的顺序。