在MapReduce for CouchDB中选择属于用户的n个元素

时间:2011-02-17 05:03:26

标签: javascript couchdb mapreduce

请耐心等待,我对整个CouchDb的东西都很陌生。

db看起来像:

** item ** count ** user **
   A       20       bob
   B       30       bob
   C       10       bob
   D       15       john

我想写一个MapReduce,它选择属于bob的所有项目,只返回前2个,排序。所以它应该返回[{item:"B",count:"30"},{item:"A",count:"20}]

我不确定如何做到这一点?好像我必须发出(doc.item,doc.count),但我怎么知道用户是否拥有该文档?如何运行另一个MapReduce来选择顶部元素?

2 个答案:

答案 0 :(得分:2)

一种解决方案是编写视图以使用复杂的密钥,例如:

function (doc) {
    emit([doc.user, doc.count], doc.item);
}

如果您在查询字符串中添加descending=true,那么会为您提供如下结果:

{"total_rows":4,"offset":0,"rows":[
    {"id":"53f359b7cd360da296dd9aab3d0029bd","key":["john",15],"value":"D"},
    {"id":"53f359b7cd360da296dd9aab3d001a0e","key":["bob",30],"value":"B"},
    {"id":"53f359b7cd360da296dd9aab3d000fec","key":["bob",20],"value":"A"},
    {"id":"53f359b7cd360da296dd9aab3d002668","key":["bob",10],"value":"C"}
]}

它已由用户排序,然后计数。 (项目类型为值)

然后您可以使用_list function来完成剩下的工作。下面的代码基本上循环遍历视图,并返回每个用户的前2个结果。如果您在查询字符串中指定user=bob,则只会获得bob的结果。

function (head, req) {
    // specify that we're sending JSON as our response
    provides('json', function () {
        var results = [],
            result, user, count, row;

        while (row = getRow()) {
            // if the user doesn't match the last iteration, reset our counter
            if (user != row.key[0]) {
                user = row.key[0];
                count = 0;
            }

            // we only need the top 2
            if (count++ >= 2) {
                continue;
            }

            // start building a result object
            result = {
                item: row.value,
                count: row.key[1]
            };

            // if we provide user=?
            if (req.query.user) {
                // check to see if it matches the current user
                if (req.query.user === user) {
                    // if so, add it to the results
                    results.push(result);
                }
            // by default, we'll return the top 2 for every user
            } else {
                // add the user key to the result object
                result.user = row.key[0];
                // and add it to the result set
                results.push(result);
            }
        }

        // send outside the loop, since it needs to be sent as valid JSON
        send(JSON.stringify(results));
    });
}

答案 1 :(得分:2)

如果您将usercount放入视图的键中,则可以使用startkey=["bob",""]endkey=["bob"]来选择用户,descending=truelimit=2获得前两项。

我尝试了以下地图功能:

function(doc) {
  if(doc.user && doc.count && doc.item) {
    emit([doc.user, doc.count], doc);
  }
}

使用查询字符串?startkey=["bob",""]&endkey=["bob"]&descending=true&limit=2返回:

{"total_rows":4,"offset":1,"rows":[
{"id":"item_B_bob","key":["bob",30],"value":{"_id":"item_B_bob","_rev":"1-b23bd22fb719c7d59b045bce0932df8c","item":"B","count":30,"user":"bob"}},
{"id":"item_A_bob","key":["bob",20],"value":{"_id":"item_A_bob","_rev":"2-515bca46eab383cfeaaa2a101d180291","item":"A","count":20,"user":"bob"}}
]}

请注意: