如何在 CouchDB 中将对象属性从 reduce 合并到重新归约函数

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

本文关键字:新归约 函数 归约 合并 reduce CouchDB 属性 对象      更新时间:2023-09-26

这是我的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]);
        }
    }
}

以下是发出的键值对的结果:

https://i.stack.imgur.com/xzh8z.png

现在,我想将其简化为单个键值对,输出的值设置为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;
}

这里的结果值是减少值,这是我所期望的:https://i.stack.imgur.com/sqRfM.png

但是,当我在蒲团中将分组值设置为"无"时,这不是我想要的:

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

有人可以帮助我解决这个问题吗?

你在这里将 CouchDB 推向了它的极限——使用 reduce 函数来执行连接和所有内容。

您的问题来自这样一个事实,即 CouchDB 可能会应用零个、一个或多个 rereduce 步骤,但您的代码假设将只执行一个 rereduce 步骤。我怀疑你得到null结果来自这样一个事实,即最终的rerere步骤应用于来自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视图,reduce步骤输出的数据必须与rereduce步骤输出的数据格式相同。特别是,这意味着您需要存储(求和,计数)对,而不是存储平均值。

如果您可以将头衔和薪水放在同一个员工文档中,这将使您的生活更加轻松。

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

然后,您可以使用内置的_stats减少功能轻松emit(doc.title, doc.salary),并查看每个标题的工资统计数据。