Получение Иерархическую Вложенность Данных В 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), и захватите дополнительные уровни, снова запустив запрос.- каким-то образом сохранить список потомки каждого узла внутри узла (это дорого).
- храните список родителей каждого узла внутри узла.