2011-02-17 49 views
1

请耐心等待,我对整个CouchDb的东西都很陌生。在CouchDB的MapReduce中选择属于用户的n个元素

的DB的样子:

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

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

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

回答

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)); 
    }); 
} 
+0

+1很好的答案。您可能想强调`_list`函数是* optional *,它仅为客户端增加了便利性/一致性,但与直接查看查询相比,没有*基本*更改。这可能有助于表明答案非常简单!然后有一个奖励练习,使其完美。 – JasonSmith 2011-02-19 08:50:44

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"}} 
]} 

请注意: