Получение Иерархическую Вложенность Данных В 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 6

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