从CouchDB中检索分层/嵌套数据

ber*_*erg 6 couchdb nested hierarchy hierarchical-data

我对couchDB很新,甚至在阅读之后(最新的存档已删除)http://wiki.apache.org/couchdb/How_to_store_hierarchical_data(通过'存储每个节点的完整路径作为该节点文档中的属性')它还没有点击.

而不是使用维基中描述的完整路径模式,我希望将子项跟踪为UUID数组,父项作为单个UUID.我倾向于这种模式,所以我可以通过他们在儿童阵列中的位置维持孩子的顺序.

以下是沙发中的一些示例文档,存储桶可以包含存储桶和项目,项目只能包含其他项目.(UUID缩写为清晰):

{_id: 3944
 name: "top level bucket with two items"
 type: "bucket",
 parent: null
 children: [8989, 4839]
}
{_id: 8989
 name: "second level item with no sub items"
 type: "item"
 parent: 3944
}
{
 _id: 4839
 name: "second level bucket with one item"
 type: "bucket",
 parent: 3944
 children: [5694]
}
{
 _id: 5694
 name: "third level item (has one sub item)"
 type: "item",
 parent: 4839,
 children: [5390]
}
{
 _id: 5390
 name: "fourth level item"
 type: "item"
 parent: 5694
}
Run Code Online (Sandbox Code Playgroud)

是否可以通过map函数中的嵌入文档ID查找文档?

function(doc) {
    if(doc.type == "bucket" || doc.type == "item")
        emit(doc, null); // still working on my key value output structure
        if(doc.children) {
            for(var i in doc.children) {
                // can i look up a document here using ids from the children array?
                doc.children[i]; // psuedo code
                emit(); // the retrieved document would be emitted here
            }
        }
     }
}   
Run Code Online (Sandbox Code Playgroud)

在理想的世界中,最终的JSON输出看起来像.

{"_id":3944,
 "name":"top level bucket with two items",
 "type":"bucket",
 "parent":"",
 "children":[
     {"_id":8989, "name":"second level item with no sub items", "type":"item", "parent":3944},
     {"_id": 4839, "name":"second level bucket with one item", "type":"bucket", "parent":3944, "children":[
         {"_id":5694", "name":"third level item (has one sub item)", "type":"item", "parent": 4839, "children":[
             {"_id":5390, "name":"fourth level item", "type":"item", "parent":5694}
         ]}
     ]}
 ]
}
Run Code Online (Sandbox Code Playgroud)

Vic*_*let 7

你能从视图中输出树结构吗?CouchDB的号视图的查询返回值的列表,有没有办法让它们比列表中的其他任何输出.因此,您必须处理您的地图,返回给定存储桶的所有后代的列表.

但是,您可以_list在视图本身之后插入后处理函数,以将该列表转换回嵌套结构.如果您的值知道_id他们的父级,这是可能的- 算法相当简单,如果它给您带来麻烦,只需询问另一个问题.

你能在map函数中通过id获取文档吗?没有.没有办法从CouchDB中通过其标识符获取文档.请求必须来自应用程序,可以GET是文档标识符上的标准形式,也可以是添加include_docs=true到视图请求中.

技术原因非常简单:CouchDB仅在文档更改时运行map函数.如果A允许文档获取文档B,则B更改时发出的数据将变为无效.

你可以输出所有后代而不存储每个节点的父亲列表吗?CouchDB映射函数为数据库中的每个文档发出一组键值id对,因此必须根据单个文档确定键和id之间的对应关系.

如果你有一个四级树结构A -> B -> C -> D但只让一个节点知道它的父节点和子节点,那么上面没有节点知道它D是一个后代A,所以你将无法使用D基于它的键发出id A因此它在输出中不可见.

所以,你有三个选择:

  • 仅获取三个级别(这是可能的,因为B知道它C是后代A),并通过再次运行查询来获取其他级别.
  • 以某种方式存储节点内每个节点的后代列表(这是昂贵的).
  • 存储节点中每个节点的父节点列表.


Mar*_*cio 6

您可以在CouchDB wiki上找到一般性讨论.

我现在没时间测试它,但是你的地图功能应该类似于:

function(doc) {
    if (doc.type === "bucket" || doc.type === "item")
        emit([ doc._id, -1 ], 1);
        if (doc.children) {
            for (var i = 0, child_id; child_id = doc.children[i]; ++i) {
                emit([ doc._id, i ], { _id: child_id });
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您应该查询它include_docs=true以获取文档,如CouchDB文档中所述:如果您的map函数发出一个对象值,{'_id': XXX}并且您使用include_docs=true参数查询视图,那么CouchDB将获取ID为XXX的文档而不是已处理的文档发出键/值对.

添加startkey=["3944"]&endkey["3944",{}]以仅获取ID为"3944"的文档及其子项.

编辑:有关详细信息,请查看此问题.