这是我的JSON架构:
{"emp_no": ..,
"salary": ..,
"from_date": ..,
"to_date": ..,
"type" : "salaries"}
{"emp_no": ..,
"title": ..,
"from_date": ..,
"to_date" : ..,
"type" : "titles"}
我想做的是找到每个活跃标题的平均工资。活动标题是“from_date”属性设置为“9999-01-01”
的文档这是我的地图功能
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]);
}
}
}
以下是生成的键值对:
现在,我想将它缩减为单个键值对,输出的值被设置为像这样的javascript对象
{
"engineer" : 64342,
"senior engineer" : 123111,
"staff" : ...,
"senior staf" : ...,
.
.
.
}
这是我计划如何做到的:首先,在reduce步骤中,我将返回合并来自同一emp_no的属性的对象。然后,在reduce步骤中,我将创建一个新对象,该对象具有基于之前减少的值的属性名称。
很难解释,所以这是我的reduce函数:
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;
}
此处的结果值是减少的值,这是我所期望的: http://i.imgur.com/SnlOU.png
但是,当我在蒲团中将分组值设置为“无”时,这不是我想要的:
{Senior Engineer: null, Assistant Engineer: null, Technique Leader: null}
有人可以帮我解决这个问题吗?
答案 0 :(得分:2)
你在这里推动CouchDB非常接近它的极限 - 使用reduce函数来执行连接和所有事情。
您的问题来自于CouchDB可能会应用零个,一个或多个重新减少步骤这一事实,但您的代码假定将执行一个重新减少步骤。我怀疑你得到的null
结果来自最终的rereduce步骤适用于来自reduce步骤的一些结果以及来自rereduce步骤的一些结果。
这是一张小图。 M是映射步骤,R是缩减步骤,RR是重新缩减步骤。
[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]
使用CouchDB减少视图时,reduce步骤输出的数据必须与rereduce步骤输出的数据格式相同。特别是,这意味着您需要存储(求和,计数)对,而不是存储平均值。
答案 1 :(得分:0)
如果您可以将标题和薪水放在同一份员工文件中,这将使您的生活更轻松。
{
"name" : "Joe",
"title" : "Plumber",
"salary" : 60000
}
然后您可以使用内置的emit(doc.title, doc.salary)
reduce函数轻松_stats
并获取每个标题的工资统计信息。