Получение Иерархическую Вложенность Данных В CouchDB
Я довольно новичок в couchDB и даже после прочтения (Последний архив, как сейчас удален) http://wiki.apache.org/couchdb/How_to_store_hierarchical_data (через ' сохранить полный путь к каждому узлу в качестве атрибута в документе этого узла’) он все еще не щелкнул.
Вместо использования полного шаблона пути, как описано в wiki, я надеюсь отслеживать детей как массив UUID, а родителя как один UUID. Я склоняюсь к этой модели, чтобы я мог поддерживать порядок расположения детей по их позициям в детском массиве.
Вот некоторые примеры документов в диване, ведра могут содержать ведра и элементы, элементы могут содержать только другие элементы. (UUIDs сокращенно для ясности):
{_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
}
Можно ли искать документ по встроенному идентификатору документа в функции карты?
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
}
}
}
}
В идеальном мире конечный вывод 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}
]}
]}
]
}
2 ответа:
Вы можете найти общую дискуссиюна 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 }); } } } }
Вы должны запросить его с помощью
include_docs=true
, чтобы получить документы, как описано в документации CouchDB: Если ваша функция map выдает значение объекта, которое имеет{'_id': XXX}
, и вы запрашиваете представление с параметромinclude_docs=true
, то CouchDB получит документ с идентификатором XXX, а не документ, который был обработан для получения документов. выделите пару ключ / значение.Добавьте
startkey=["3944"]&endkey["3944",{}]
, чтобы получить только документ с идентификатором "3944" с его дочерними элементами.EDIT: посмотрите на этот вопрос для получения более подробной информации.
Можно ли вывести древовидную структуру из представления? Нет. Запросы представления CouchDB возвращают список значений, нет никакого способа заставить их выводить что-либо, кроме списка. Таким образом, вы должны иметь дело с вашей картой, возвращающей список всех потомков данного ведра.
Вы можете, однако, подключить a
_list
функция постобработки после самого представления, чтобы превратить этот список обратно во вложенную структуру. Это возможно, если ваши значения знают_id
своего родителя - алгоритм довольно прост, просто задайте другой вопрос, если это доставляет вам проблемы.Можно ли захватить документ по его идентификатору в функции map? Нет. Нет никакого способа захватить документ по его идентификатору из CouchDB. Запрос должен исходить из приложения либо в виде стандартного
GET
идентификатора документа, либо путем добавленияinclude_docs=true
к запросу представления.Техническая причина этого довольно проста: CouchDB запускает функцию map только тогда, когда изменения в документе. Если бы документ
A
был разрешен для извлечения документаB
, то при измененииB
исходящие данные становились бы недействительными.Можно ли вывести все потомки без сохранения списка родителей каждого узла? Нет. Функции CouchDB map выделяют набор пар ключ-значение-идентификатор для каждого документа в базе данных, поэтому соответствие между ключом и идентификатором должно определяться на основе одного документа.
Если у вас есть четырехуровневая древовидная структура
A -> B -> C -> D
но только дайте узлу знать о его родителе и потомках, тогда ни один из вышеперечисленных узлов не будет знать, чтоD
является потомкомA
, поэтому вы не сможете выдать идентификаторD
с ключом, основанным наA
, и, таким образом, он не будет виден в выходных данных.Итак, у вас есть три варианта:
- захватите только три уровня (это возможно, потому что
B
знает, чтоC
является потомкомA
), и захватите дополнительные уровни, снова запустив запрос.- каким-то образом сохранить список потомки каждого узла внутри узла (это дорого).
- храните список родителей каждого узла внутри узла.