Облачный непоследовательный пересчет "списка" результатов подсчета узлов в дереве
У нас есть дерево страниц на страницах, представленных в базе данных со следующей схемой:
{"_id":"xxx","table":"user_page","user_id":user2,"page_id":page1,"ancestors":[page2,page3],"count":{"active":1,"unread":1},"count_if":{"active":1,"unread":1}}
Наша цель - получить различные типы счетчиков для узлов в дереве (страницы)
Наш mapfn выглядит следующим образом:
function(doc) {
if (doc.table=="user_page") {
emit([doc.page_id, doc.user_id], {ancestors: doc.ancestors, count: doc.count, count_if: doc.count_if});
if (doc.ancestors.length > 0){
for(var i in doc.ancestors){
emit([doc.ancestors[i], doc.user_id], {ancestors: doc.ancestors, count: doc.count, count_if: doc.count_if});
}
}
}
}
Наш mapfn производит данные в этой форме:
{"id":"yy","key":[page1,user2],"value":{"ancestors":[page2,page3]"count":{"active":1,"unread":1},"count_if":{"active":1,"unread":1}}}
{"id":"zz","key":[page2,user2],"value":{"ancestors":[page2,page3]"count":{"active":1,"unread":1},"count_if":{"active":1,"unread":1}}}
{"id":"ww","key":[page3,user2],"value":{"ancestors":[page2,page3]"count":{"active":1,"unread":1},"count_if":{"active":1,"unread":1}}}
Наше сокращение fn выглядит следующим образом:
function reduceFn(key, values, rereduce) {
if(rereduce){
var result_object = {}, out_array = {}, reduce_pages = {};
// first convert values array to an object-- values_object = {page1: {}, page2:{}, etc.}
for (var i in values) {
if (values[i].value) {
var record = values[i].value;
var page_id = record.page_id;
reduce_pages[page_id] = record;
result_object[page_id] = {"active":0,"unread":0};
}
}
// reduce_pages (object) is a copy of incoming values array
// result_object will be the result of the reduce keyed by page_id
for(var pages in reduce_pages){ // go through each page in values
if(reduce_pages[pages]){
var local_obj = reduce_pages[pages];
var page_id = local_obj.page_id;
var ancestors = local_obj.ancestors;
for (var itr in ancestors) { // go through each ancestor in the current page being calculated
var this_ancestor = ancestors[itr];
if(this_ancestor!=page_id && reduce_pages[this_ancestor]){
var single_obj = reduce_pages[this_ancestor]; // get the record associated with this ancestor
var single_obj_page_id = single_obj.page_id;
// now update each of the result objects for each ancestor
if (single_obj.count_if.active) {
result_object[single_obj_page_id].active = result_object[single_obj_page_id].active+ single_obj.count.active;
}
if (single_obj.count_if.unread) {
result_object[single_obj_page_id].unread = result_object[single_obj_page_id].unread + single_obj.count.unread;
}
}
}
}
}
// now convert result_object to an array
if (Object.keys(result_object).length > 0) {
for (var j in result_object) {
if (Object.keys(result_object[j]).length) {
out_array[j] = result_object[j];
}
}
}
return out_array;
}else{
return values;
}
}
Javascript в браузере дает правильные результаты {"page1": {"active": 11, "unread":11}
Но в Cloudnat нет, то есть {"page1":{"active":9,"непрочитано":9}
Есть идеи? Это потому, что мы пытаемся вернуть список из редукции?