How to merge objects attributes from reduce to rereduce function in CouchDB

青春壹個敷衍的年華 提交于 2019-12-12 09:19:56

问题


This is my JSON schema:

{"emp_no": ..,
"salary": ..,
"from_date": ..,
"to_date": ..,
"type" : "salaries"}

{"emp_no": ..,
"title": ..,
"from_date": ..,
"to_date" : ..,
"type" : "titles"}

What i wanted to do, is to find the average salary for each active title. Active titles are document with "from_date" attribute set to "9999-01-01"

Here is my Map Function

function(doc) {
if (doc.type == 'salaries') {
        var dateSalaries = null;
        dateSalaries = doc.to_date.split("-");
        if(dateSalaries[0].localeCompare("9999") == 0){
            emit(doc.emp_no, ["salary", doc.salary] );
        }
    } else if (doc.type == 'titles') {
        var dateTitles = null;
        dateTitles = doc.to_date.split("-");
        if(dateTitles[0].localeCompare("9999") == 0){
            emit(doc.emp_no, ["title", doc.title]);
        }
    }
}

Here is the resulting key value pairs emited:

http://i.imgur.com/o1Qxz.png

Now, i want to reduce it into single key-value pair, with the value outputted is set into javascript object like this

{
    "engineer" : 64342,
    "senior engineer" : 123111,
    "staff" : ...,
    "senior staf" : ...,
    .
    .
    .
}

Here's how i planned to do it: First, in reduce step, i'm gonna return object that merge properties from the same emp_no. Then, in reduce step, i'm gonna create a new object that has properties name based on reduced value before.

It's hard to explain, so here is my reduce function:

function(keys, values, rereduce) {
    var i, l, attr, sal, rv = {};
    if (rereduce) {
        for (i = 0, l = values.length; i<l ; ++i) {
            if (values[i].hasOwnProperty('salary')) {
                attr = values[i].title;
                sal = values[i].salary;
                if (rv[attr] instanceof Array) {
                    rv[attr].push(sal);
                } else{
                    rv[attr] = [];
                    rv[attr].push(sal);
                }
            }           
        }

        for (var x in rv) {
            if (rv.hasOwnProperty(x)) {
                var totalSalary = 0;
                for (i = 0, l = values.length; i<l ; i++) {
                    totalSalary += rv[x][i];
                }
                rv[x] = totalSalary / rv[x].length;
            }
        }

    } else {
        for (i = 0, l = values.length; i<l ; i++) {
            switch (values[i][0]) {
                case "title" : rv["title"] = values[i][1]; break;
                case "salary": rv["salary"] = values[i][1]; break;
            }
        }
    }
    return rv;
}

The resulting value here is reduced value, which is what i expected: http://i.imgur.com/SnlOU.png

But, when i set the grouping value to 'none' in futon, it's not what i wanted:

{Senior Engineer: null, Assistant Engineer: null, Technique Leader: null}

Could someone help me to solves this?


回答1:


You're pushing CouchDB pretty close to its limits here — using a reduce function to perform a join and everything.

Your problem comes from the fact that CouchDB may apply zero, one or more rereduce steps, but your code assumes that exactly one rereduce step will be performed. I suspect the null results you get come from the fact that the final rereduce step is applied to some results that come from a reduce step and some results that come from a rereduce step.

Here's a small diagram. M is a map step, R is a reduce step, RR is a rereduce step.

[X] [X] [X] [X] [X] [X] [X] [X] [X] [X] 
 |   |   |   |   |   |   |   |   |   | 
(M) (M) (M) (M) (M) (M) (M) (M) (M) (M)
 |   |   |   |   |   |   |   |   |   | 
(==R==) (==R==) (==R==) (==R==) (==R==)
   |       |       |       |       | 
  (== R R ==)     (== R R ==)      | 
       |               |           | 
      (====== R R ======)          | 
               |                   | 
              (======== R R ========)
                         |
                         v
                        [X]

With CouchDB reduce views, it is essential that the data output by your reduce step has the same format as the data output by your rereduce steps. In particular, this means that instead of storing averages, you need to store (sum,count) pairs.




回答2:


It would make your life a lot easier if you could put the title and salary in the same employee document together.

{
"name" : "Joe",
"title" : "Plumber",
"salary" : 60000
}

then you could easily emit(doc.title, doc.salary) with the built-in _stats reduce function and get a view of salary stats for each title.



来源:https://stackoverflow.com/questions/11207961/how-to-merge-objects-attributes-from-reduce-to-rereduce-function-in-couchdb

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!