CouchDB视图每个键减少一个文档

问题描述 投票:0回答:1

我正在尝试使用SofaDb视图解决似乎很简单的问题,但我的结果集甚至还没有接近目标。

而不是更新文档,而是每次都创建一个新文档作为版本控制策略,并将这些文档与一个名为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函数返回两条记录,这不是我想要的。我正在尝试实现的目标是否可行?或者是否有更好的方法来解决此问题?

更新

当我使用一个键访问视图时,这是我的用例之一。

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;
}

但是,我还有另一个用例,它将返回视图中的所有数据。所需的结果与上面的结果相同,但是我用于单键的功能只会返回一个结果。如何使用共享密钥过滤多个值,例如1个“共享”密钥:n个值-> 1个密钥:1个值。

mapreduce couchdb document-versioning
1个回答
0
投票

当我偶然发现此couchbase article时,我终于能够解决此问题。它比其他一些干的计算机科学文档更加清晰。

我仍然不明白为什么某些项目以简化方法分组,而另一些则没有。例如,对于具有相同密钥的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);
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.