У меня есть набор документов на диване БД, которые действуют как дерево. Каждый документ содержит поле ancestors
, которое включает в себя список идентификаторов, которые представляют местоположение в дереве текущего документа. У некоторых документов есть значение, связанное с ними (число).
Если у документа нет собственного значения, его неявное значение является максимальным из всех его дочерних элементов. Но когда у документа есть своя собственная ценность, значение любого потомка игнорируется. Например,
- Root (без значения, без предков) эффективное значение 7
- Child1 (значение 5, предки = Root) эффективное значение 5
- Внук 1 (значение 9, предки = Root, Child1) эффективное значение 9
- Child2 (без значения, предки = Root) эффективное значение 7
- Grandchild2 ( значение 3, предки = Root, Child2) эффективное значение 3
- Grandchild3 (значение 7, предки = Root, Child2) эффективное значение 7
- Child3 ( значение 6, предки = Root) эффективное значение 6
Я пытаюсь построить представление, которое позволяет мне получить эффективное значение для данного узла (я буду иметь полный путь, чтобы можно было указать путь или идентификатор). Итак, я пытаюсь сделать следующее:
- Излучить все, что имеет явное значение, в моей функции карты
- Создать функцию приведения, которая возвращает явное значение для узла, если он имеет один или находит максимальное число его дочерних элементов, если это не так.
Я изо всех сил пытаюсь сделать эту работу, потому что, кажется, сокращение выполняется на разделах данных. Поэтому я продолжаю получать сценарий ios, где ребенок и родитель не собираются вместе до повторного сокращения, поэтому я теряю отношения и получаю неправильное значение. например, с указанным выше деревом:
- Grandchild 1 (значение 9) и Grandchild 3 (значение 7) попадают в один и тот же раздел, поэтому сначала уменьшаются, что приводит к значению 9
- Child Значение 1 (значение 5) уменьшается для ребенка 3 (значение 6), в результате чего значение 6 становится выигрышным, а знания о ребенке 1
- уменьшаются. Повторное уменьшение происходит для уменьшения ребенка 3 (значение 6) и внука 1 (значение 9), а результирующее значение равно 9, поскольку дочерний элемент 1 не участвует в этом уменьшении, мы не знаем, что на самом деле следует заменить 9 на 5, поэтому мы получаем неправильный результат.
Возможно ли реализовать эту логику c в функции уменьшения вида дивана?
Мои текущие реализации:
Функция карты
function (doc) {
if (doc.ancestors && doc.data) {
// For anything with a value emit it with the full path as the key
var path = doc.ancestors.concat([doc._id]);
emit(path, {data: doc.data, path: path})
}
}
Функция уменьшения
function (keys, values, rereduce) {
// build a tree of the values currently being reduced
// by reassembling the paths and putting the value
// at the targeted location
var tree = {children: {}};
function addValueToTree(value) {
var parent = tree;
value.path.forEach(function(docId) {
var newParent = parent.children[docId] || {children: {}};
parent.children[docId] = newParent;
parent = newParent;
});
parent.value = value;
}
values.forEach(addValueToTree);
// Object.entries isn't supported in Couch JS
// engine so simple polyfill
function entries(obj) {
var entries = [];
for (k in obj) {
entries.push([k, obj[k]]);
}
return entries;
}
// Determine the value of the tree selecting
// the one "winning" value to return from the
// reduce function
function reduceTree(tree, path) {
// If the node of the tree we're reducing has an
// explicit value then return that since it should
// take precedence over any children
if (tree.value) {
return tree.value;
}
// Otherwise reduce the children of the current node
// to get the "winning" node from
var toCombine = entries(tree.children).map(function (entry) {
return reduceTree(entry[1], path.concat([entry[0]]));
});
// Find the winning child by picking the one with
// the maximum value and return that
var ret = toCombine[0];
toCombine.forEach(function(child) {
if (child.data > ret.data)
ret = child;
});
return ret;
}
var ret = reduceTree(tree, []);
log({values: values, ret: ret})
return ret;
}
Это работает до тех пор, пока потомки сокращаются в одном и том же вызове с любыми родительскими узлами, которые должны иметь приоритет, но когда родительский элемент в конечном итоге удаляется из уменьшить (как в примере выше) означает, что потомок не заменяется и может в конечном итоге повлиять на окончательный расчет, что приведет к неверному результату.
Я пытался собрать «вспомогательные узлы» при сокращении, чтобы мы сохранили знания, необходимые для того, чтобы знать, что узел перезаписывается, но это приводит к ошибке «функция сокращения фактически не уменьшает данные».
Возможно ли это даже с функцией уменьшения или это принципиально нарушает ограничения функции сокращения?