Как я могу вызвать другое представление в представлении couchdb? - PullRequest
5 голосов
/ 29 июля 2010

Я только что закончил книгу «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. Точнее говоря, с переходными отношениями между элементами.

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

Ответы [ 2 ]

8 голосов
/ 30 июля 2010

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

1 голос
/ 29 июля 2010

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

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" } ]

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...