CouchDB 视图每个键减少一个文档
CouchDB view reduce one doc per key
我正在尝试用 couchDb 视图解决看似相当简单的问题,但我什至没有接近我的结果集的目标。
我不是更新文档,而是每次都创建一个新文档作为我的版本控制策略,并将这些文档与一个名为 ver
的版本控制字段绑定在一起。版本链中的第一个文档将看到 ver
字段和 _id
字段具有相同的值。链中的所有后续文档将具有与链中先前文档相同的 ver
字段,但将具有唯一的 _id
字段。这些文档还有一个 createdTime
字段,这是我了解哪个文档是最新的方式。
这是我的文件:
{
"_id": "abcd-1234-efgh-9876",
"ver": "abcd-1234-efgh-9876",
"createdTime": "2020-01-12 01:15:00 PM -0600",
...
},
{
"_id": "uopa-3849-pmdi-1935",
"ver": "abcd-1234-efgh-9876",
"createdTime": "2020-02-16 02:39:00 PM -0600",
...
}
这是我的地图函数:
function (doc) {
emit(doc.ver, doc);
}
这是我的 reduce 函数:
function(keys, values, rereduce) {
var latestVersions = {};
for (var i = 0; i < keys.length; i++) {
var found = latestVersions[keys[i][0]];
if (!found || found.createdTime < values[i].createdTime) {
latestVersions[keys[i][0]] = values[i];
}
}
return latestVersions;
}
最后,这是我想要的视图输出(只是我想要的文档):
{
"_id": "uopa-3849-pmdi-1935",
"ver": "abcd-1234-efgh-9876",
"createdTime": "2020-02-16 02:39:00 PM -0600",
...
}
我在这里错过了什么? reduce 函数是 returning 两条记录,这不是我想要的。我正在努力实现的目标是可行的还是有更好的方法?
更新
当使用单个键访问视图时,我能够使它工作,这是我的一个用例。
function (keys, values, rereduce) {
var toReturn = values[0];
for (var i = 1; i < values.length; i++) {
if (values[i].createdTime > toReturn.createdTime) {
toReturn = values[i];
}
}
return toReturn;
}
不过,我还有另一个用例,它将 return 处理视图中的所有数据。所需的结果与上面相同,但我用于单键的函数只会 return 一个结果。如何使用共享密钥过滤多个值,以便 1 "shared" key:n 值 -> 1 key:1 值。
当我偶然发现这个 couchbase article 时,我终于能够解决这个问题。它比其他一些枯燥的计算机科学文档更清晰。
我仍然不明白为什么某些项目在 reduce 方法中分组,而其他项目却没有。例如,对于共享相同键的 6 个项目,reduce 被调用了 5 次;只有一个键实际上对任何东西进行了分组——两个文档的数组。这可能与我忽略的那些枯燥的计算机科学 B 树文档有关。
无论如何,我能够确定我需要做的就是在两种情况下按 ver
字段对值进行分组(唯一的区别是 rereduce 有一个二维数组)。这是我的 reduce 函数最终的样子:
function (keys, values, rereduce) {
var toValues = function(myMap) {
return Object.keys(myMap).map(function(key) {
return myMap[key];
});
}
if (rereduce) {
// values should look like [[{...}, {...}], [{...}]]
var outputMap = {};
for (var i = 0; i < values.length; i++) {
for (var j = 0; j < values[i].length; j++) {
var currentEl = values[i][j];
var found = outputMap[currentEl.ver];
if ((found && found.createdDate < currentEl.createdDate) || !found) {
outputMap[currentEl.ver] = currentEl;
}
}
}
return toValues(outputMap);
} else {
var outputMap = {};
for (var i = 0; i < values.length; i++) {
var found = outputMap[values[i].ver];
if ((found && found.createdDate < values[i].createdDate) || !found) {
outputMap[values[i].ver] = values[i];
}
}
return toValues(outputMap);
}
}
我正在尝试用 couchDb 视图解决看似相当简单的问题,但我什至没有接近我的结果集的目标。
我不是更新文档,而是每次都创建一个新文档作为我的版本控制策略,并将这些文档与一个名为 ver
的版本控制字段绑定在一起。版本链中的第一个文档将看到 ver
字段和 _id
字段具有相同的值。链中的所有后续文档将具有与链中先前文档相同的 ver
字段,但将具有唯一的 _id
字段。这些文档还有一个 createdTime
字段,这是我了解哪个文档是最新的方式。
这是我的文件:
{
"_id": "abcd-1234-efgh-9876",
"ver": "abcd-1234-efgh-9876",
"createdTime": "2020-01-12 01:15:00 PM -0600",
...
},
{
"_id": "uopa-3849-pmdi-1935",
"ver": "abcd-1234-efgh-9876",
"createdTime": "2020-02-16 02:39:00 PM -0600",
...
}
这是我的地图函数:
function (doc) {
emit(doc.ver, doc);
}
这是我的 reduce 函数:
function(keys, values, rereduce) {
var latestVersions = {};
for (var i = 0; i < keys.length; i++) {
var found = latestVersions[keys[i][0]];
if (!found || found.createdTime < values[i].createdTime) {
latestVersions[keys[i][0]] = values[i];
}
}
return latestVersions;
}
最后,这是我想要的视图输出(只是我想要的文档):
{
"_id": "uopa-3849-pmdi-1935",
"ver": "abcd-1234-efgh-9876",
"createdTime": "2020-02-16 02:39:00 PM -0600",
...
}
我在这里错过了什么? reduce 函数是 returning 两条记录,这不是我想要的。我正在努力实现的目标是可行的还是有更好的方法?
更新
当使用单个键访问视图时,我能够使它工作,这是我的一个用例。
function (keys, values, rereduce) {
var toReturn = values[0];
for (var i = 1; i < values.length; i++) {
if (values[i].createdTime > toReturn.createdTime) {
toReturn = values[i];
}
}
return toReturn;
}
不过,我还有另一个用例,它将 return 处理视图中的所有数据。所需的结果与上面相同,但我用于单键的函数只会 return 一个结果。如何使用共享密钥过滤多个值,以便 1 "shared" key:n 值 -> 1 key:1 值。
当我偶然发现这个 couchbase article 时,我终于能够解决这个问题。它比其他一些枯燥的计算机科学文档更清晰。
我仍然不明白为什么某些项目在 reduce 方法中分组,而其他项目却没有。例如,对于共享相同键的 6 个项目,reduce 被调用了 5 次;只有一个键实际上对任何东西进行了分组——两个文档的数组。这可能与我忽略的那些枯燥的计算机科学 B 树文档有关。
无论如何,我能够确定我需要做的就是在两种情况下按 ver
字段对值进行分组(唯一的区别是 rereduce 有一个二维数组)。这是我的 reduce 函数最终的样子:
function (keys, values, rereduce) {
var toValues = function(myMap) {
return Object.keys(myMap).map(function(key) {
return myMap[key];
});
}
if (rereduce) {
// values should look like [[{...}, {...}], [{...}]]
var outputMap = {};
for (var i = 0; i < values.length; i++) {
for (var j = 0; j < values[i].length; j++) {
var currentEl = values[i][j];
var found = outputMap[currentEl.ver];
if ((found && found.createdDate < currentEl.createdDate) || !found) {
outputMap[currentEl.ver] = currentEl;
}
}
}
return toValues(outputMap);
} else {
var outputMap = {};
for (var i = 0; i < values.length; i++) {
var found = outputMap[values[i].ver];
if ((found && found.createdDate < values[i].createdDate) || !found) {
outputMap[values[i].ver] = values[i];
}
}
return toValues(outputMap);
}
}