我的文档文档的简单版本是以下结构:
doc:
{
"date": "2014-04-16T17:13:00",
"key": "de5cefc56ff51c33351459b88d42ca9f828445c0",
}
我想按密钥对文档进行分组,以获取每个密钥的最新日期和文档数量,例如
{ "Last": "2014-04-16T16:00:00", "Count": 10 }
我的想法是将地图/缩小视图和查询设置组设为真 这是我到目前为止所尝试的。我得到了确切的计数,但没有正确的日期。
function (doc, meta) {
if(doc.type =="doc")
emit(doc.key, doc.date);
}
function(key, values, rereduce) {
var result = {
Last: 0,
Count: 0
};
if (rereduce) {
for (var i = 0; i < values.length; i++) {
result.Count += values[i].Count;
result.Last = values[i].Last;
}
} else {
result.Count = values.length;
result.Last = values[0]
}
return result;
}
答案 0 :(得分:2)
您没有比较日期... Couchbase按键对值进行排序。在您的情况下,它不会按日期排序,因此您应该在reduce函数中手动执行此操作。可能它看起来像:
result.Last = values[i].Last > result.Last ? values[i].Last : result.Last;
并且在reduce函数中它也可以是一个数组,所以我不认为你的reduce函数总是正确的。
这是我的reduce函数的一个示例,它过滤文档并只保留一个具有最新日期的文档。可能它会有所帮助,或者你可以尝试使用它(看起来它看起来像你想要的reduce函数,你只需要在某处添加计数)。
function(k,v,r){
if (r){
if (v.length > 1){
var m = v[0].Date;
var mid = 0;
for (var i=1;i<v.length;i++){
if (v[i].Date > m){
m = v[i].Date;
mid = i;
}
}
return v[mid];
}
else {
return v[0] || v;
}
}
if (v.length > 1){
var m = v[0].Date;
var mid = 0;
for (var i=1;i<v.length;i++){
if (v[i].Date > m){
m = v[i].Date;
mid = i;
}
}
return v[mid];
}
else {
return v[0] || v;
}
}
UPD:这是一个减少的例子: 该函数的输入日期(值)看起来像(我只使用数字而不是文本日期来缩短它):
[{Date:1},{Date:3},{Date:8},{Date:2},{Date:4},{Date:7},{Date:5}]
第一步rereduce将是false
,所以我们需要在数组中找到最大的日期,它将返回
Object {Date: 8}
。
请注意,此函数可以调用一次,但可以在集群中的多个服务器上调用,也可以在一个couchbase实例内的b-tree的多个分支上调用。
然后在下一步(如果群集中有多台计算机或#34;分支&#34;)rereduce
将被调用,rereduce
var将设置为true
< / p>
传入的数据将是:
[{Date:8},{Date:10},{Date:3}]
,其中{Date:8}
来自一个服务器(或分支),而其他日期来自另一个服务器(或分支)。
所以我们需要在新值上做同样的事情才能找到最大值。
从评论中回答你的问题:我不记得为什么我使用相同的代码进行reduce和rereduce,因为它很久以前(当couchbase 2.0处于开发预览版时)。可能是沙发基有一些错误,或者我只是想了解rereduce是如何工作的。但我记得没有那个if (r) {..}
它当时没有用。
您可以尝试将return v;
代码放在我或您的reduce函数的不同部分,以查看它在每个reduce阶段返回的内容。最好自己尝试一次,以了解那里发生的事情。
答案 1 :(得分:1)
我忘记提到我有相同密钥的许多文档。事实上,对于每个键,我可以有很多文档(此处有消息):
{
"date": "2014-04-16T17:13:00",
"key": "de5cefc56ff51c33351459b88d42ca9f828445c0",
"message": "message1",
}
{
"date": "2014-04-16T15:22:00",
"key": "de5cefc56ff51c33351459b88d42ca9f828445c0",
"message": "message2",
}
解决问题的另一种方法是在map函数中执行此操作:
function (doc, meta) {
var count = 0;
var last =''
if(doc.type =="doc"){
for (k in doc.message){
count += 1;
last = doc.date> last?doc.date:last;
}
emit(doc.key,{'Count':count,'Last': last});
}
}
我发现这个更简单,它可以完成我的工作。