减少 CouchDB 中的多个字段值

Reduce multiple field values in CouchDB

对于通知系统,我将用户消息存储在 CouchDB 中。我的文档结构如下所示:

{
   "_id": "bc325c2f6a99194ecab6e7bbae81b609",
   "_rev": "1-9745ddb21cefe3dbc8cc1f7f7bd8d11d",
   "uid": "bc325c2f6a99194ecab6e7bbae80eb29",
   "msg": "Hi there, here is a message for you!",
   "level": "warning",
   "status": "new",
   "created": 1467180077,
   "read": null
}

字段 status 可以有两个值 newread - 我正在尝试将 Map/Reduce 视图写入 return 某个用户的计数,包括他们有多少条状态为 new 的消息以及有多少条状态为 read.

映射函数非常简单:

function(doc) {
  emit(doc.uid, doc.status);
}

它 return 是这样的:

| key                                | value
+------------------------------------+------------------------------
| bc325c2f6a99194ecab6e7bbae80eb29   | "read"
+------------------------------------+------------------------------
| bc325c2f6a99194ecab6e7bbae80eb29   | "read"
+------------------------------------+------------------------------
| bc325c2f6a99194ecab6e7bbae80eb29   | "read"
+------------------------------------+------------------------------
| bc325c2f6a99194ecab6e7bbae80eb29   | "new"
+------------------------------------+------------------------------
| bc325c2f6a99194ecab6e7bbae80eb29   | "new"

我现在正在尝试弄清楚如何编写一个会产生此结果的 reduce 函数:

| key                                | value
+------------------------------------+------------------------------
| bc325c2f6a99194ecab6e7bbae80eb29   | ["read":3, "new":2]
+------------------------------------+------------------------------

如果我使用这个reduce函数

function (key, values, rereduce) {
    return  values;
}

我得到:

| key                                | value
+------------------------------------+------------------------------
| bc325c2f6a99194ecab6e7bbae80eb29   | ["read","read","read","new","new"]
+------------------------------------+------------------------------

我尝试使用 return count(values) 但它 returns null.

我似乎无法解决这个问题。任何人都可以让我走上正轨吗?

我找到了一种方法,但我不确定这是否是正确的方法:

reduce函数:

function (key, values, rereduce) {
    var result = new Object;
    result.read = 0;
    result.new = 0;

    for(var i = 0; i < values.length; ++i){
        if(values[i] == 'new'){
                result.new++;
        }
            if(values[i] == 'read'){
                result.read++;
        }
    };
    return result;
}

会产生这样的结果:

| key                                | value
+------------------------------------+------------------------------
| bc325c2f6a99194ecab6e7bbae80eb29   | {read: 2, new: 1}
+------------------------------------+------------------------------

我的建议是发出 uidstatus 作为您的密钥,然后您将获得作为减少值的计数。

首先,我们将从地图功能开始:

function (doc) {
  emit([ doc.uid, doc.status ]);
}

请注意,我们只发出一个键,而不是一个值。 (事实证明在这种情况下我们不需要它)

然后,使用下面的built-in reduce function

_count

您的视图输出将包含如下键:(记住,我们不关心值)

  • [ "bc325c2f6a99194ecab6e7bbae80eb29", "read" ]
  • [ "bc325c2f6a99194ecab6e7bbae80eb29", "read" ]
  • [ "bc325c2f6a99194ecab6e7bbae80eb29", "read" ]
  • [ "bc325c2f6a99194ecab6e7bbae80eb29", "new" ]
  • [ "bc325c2f6a99194ecab6e7bbae80eb29", "new" ]

查询视图时,确保包含 group=true(隐含 reduce=true

您会注意到您的视图现在有以下 key/value 对:

  • [ "bc325c2f6a99194ecab6e7bbae80eb29", "read" ]: 3
  • [ "bc325c2f6a99194ecab6e7bbae80eb29", "new" ]: 2

如果您的数据库中有更多文档,您也会看到所有其他用户 ID。要过滤到您关心的用户,只需使用:

  • startkey=["bc325c2f6a99194ecab6e7bbae80eb29"]
  • endkey=["bc325c2f6a99194ecab6e7bbae80eb29",{}]

这些数组看起来有点奇怪,我敢肯定,但它们只是确保匹配 "status" 的任何值。 (查看 Views Collation 上的文档了解更多信息)

这种方法可以很好地扩展,允许任何其他 status 值在没有任何代码更改的情况下工作。