Как я могу вызвать другое представление в представлении 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;
}
Эта функция проверяет, не является ли дочерняя часть ключа пустой, и если это так, она помещает идентификатор документа в массив. Таким образом, он перебирает все значения и возвращает массив после завершения.