Как я могу вызвать другое представление в представлении couchdb?

Я только что закончил книгу "couchdb: полное руководство" и начал играть с проектной документацией. однако есть одна вещь, которую я не понимаю. Все примеры, которые я видел до сих пор, являются несколько линейными.

Пример:

{
   "_id": "1",
   "_rev": ".....",
   "name": "first",
   "something": "blue",   
   "child": "2"   
}

{
   "_id": "2",
   "_rev": ".....",
   "name": "second",
   "something": "green",   
   "child": "3"   
   "parent" : "1"
   }

{
   "_id": "3",
   "_rev": ".....",
   "name": "second",
   "something": "red",   
   "parent" : "2";
}

У меня нет проблем с написанием представления, которое возвращает все цвета:

function(doc) {
        if (doc.something) {
            emit(doc.something,doc._id);    
    }
}

Но что, если я хочу знать всех (!) Потомков (не детей, извините за мою ошибку) для элемента с _id = 1 ("что-то": "синий")? Мой опыт программирования говорит мне, что я должен использовать рекурсию, но я не знаю как. Как я могу вызвать другую функцию просмотра из функции просмотра?

В общем: эта проблема возникает, когда вы проектируете базу данных со ссылками между документами json. В частности, с переходными отношениями между элементами.

Изменить: Для примера: я знаю только _id = 1, и результат должен быть что-то вроде [_id=2, _id=3], потому что 2 является дочерним 1 и 3 является дочерним 2.

2 ответа

Решение

Если это вообще возможно, не определяйте иерархию документов таким образом - вы будете бороться с CouchDB на каждом этапе пути.

Вы не можете действительно выполнять иерархическую прогулку в представлении. Представления предназначены для передачи каждого документа независимо друг от друга (карта) и генерирования некоторой совокупной стоимости из них (уменьшить).

Вы можете использовать списки для работы с несколькими документами одновременно, но это тоже не очень хорошее решение.

Если вам нужно сохранить эту структуру данных (ссылки на родительский / дочерний), я предлагаю вам собрать структуру извне CouchDB: получить родительский документ, получить его дочерние элементы, получить их дочерние элементы и т. Д.

Однако предпочтительный способ хранения дерева в CouchDB состоит в том, чтобы каждый узел запоминал свой путь в дереве:

{
   "_id": "1",
   "name": "first",
   "something": "blue",
   "path": [1]
}

{
   "_id": "2",
   "name": "second",
   "something": "green",
   "path": [1,2]
   }

{
   "_id": "3",
   "name": "second",
   "something": "red",
   "path": [1,2,3]
}

Затем вы можете использовать это представление для получения потомков документа:

function(doc) { 
    for (var i in doc.path) { 
        emit([doc.path[i], doc.path], doc) 
    } 
}

Чтобы получить потомков _id 1 вы можете запустить этот запрос:

http://c.com/db/_design/colors/_view/descendants?startkey=[1]&endkey=[1,{}]

Сохранение полного пути также имеет свои недостатки. Я предлагаю вам проверить эту вики-страницу CouchDB на деревьях. Источник для этого - это сообщение в блоге Пола Бонсера.

В приведенном выше примере, чтобы получить все дочерние элементы для идентификатора документа, ваша функция карты будет выглядеть примерно так:

function (doc) {
    if (doc.parent) {
        emit(doc.parent, { "_id": doc._id });
    }
}

(Свойство "child", имеющееся в документе 2, даже не обязательно.)

Учитывая данные вашего примера, это будет выдавать дважды:

[ "1", { "_id": "2" } ]
[ "2", { "_id": "3" } ]

Чтобы получить дочерние идентификаторы для одного родителя, вы должны получить доступ к представлению следующим образом:

http://.../db/_design/viewName/_view/childfunc?key="2"

Чтобы получить полный документ, добавьте параметр include_docs в строку запроса.

Если вы хотите получить родительский и дочерний элементы одновременно, функция вашей карты немного отличается:

function (doc) {
    emit([ doc._id, "" ], { "_id": doc.id });
    if (doc.parent) {
        emit([ doc.parent, doc._id ], { "_id": doc.id })
    }
}

Эта функция может излучать дважды, поэтому вы получите следующее:

[ [ "1", ""  ], { "_id": "1" } ]
[ [ "1", "2" ], { "_id": "2" } ]
[ [ "2", ""  ], { "_id": "2" } ]
[ [ "2", "3" ], { "_id": "3" } ]
[ [ "3", ""  ], { "_id": "3" } ]

Благодаря сортировке сортировки родители оказываются первыми (так как их вторым ключевым элементом является ""), а дети - после этого. Вам не нужно использовать дочерний _id в качестве второго ключевого элемента, вы можете использовать любое свойство естественной сортировки, которое будет наиболее целесообразным. (Дата создания, имя, название, что угодно.)

Если у вас не было свойства "child", вы могли бы сделать функцию Reduce для получения всех потомков родителя:

function (key, vals) {
    var children = [];
    for (var docId in vals) {
        if (key[1] !== "") {
            children.push(docId);
        }
    }
    return children;
}

Эта функция проверяет, не является ли дочерняя часть ключа пустой, и если это так, она помещает идентификатор документа в массив. Таким образом, он перебирает все значения и возвращает массив после завершения.

Другие вопросы по тегам