我有一个包含一系列事件的couchdb。每个事件都有一个所有者,一个id,一个发生的时间和一条消息(加上一堆其他的东西,这对这个练习无关紧要)。我想要一张最近发生的事件的清单,按时间排序。我查看了这个问题CouchDB -从列表中过滤每个日志实例的最新日志,并尝试将其与减速机中的比较一起使用,以保留第一条消息(使用我有一个复杂键的形式)。
不幸的是,它似乎并没有达到我想要的效果。
这是我的地图函数
function(doc) {
var owner, id;
if (doc.owner
&& doc.stream_id
&& doc.message
&& doc.receipt_time)
{
emit([doc.owner,doc.stream_id,doc.receipt_time],
{ owner: doc.owner,
stream_id: doc.stream_id,
timestamp: doc.receipt_time,
message: doc.message
});
}
}
和我的reduce函数
function(keys, values) {
var challenger, winner = null;
for (var a = 0; a < values.length; a++) {
challenger = values[a];
if (! winner) {
winner = challenger;
} else {
if (winner.owner !== challenger.owner
&& winner.trace_id !== challenger.trace_id ) {
return null;
} else if (challenger.timestamp < winner.timestamp) {
winner = challenger;
}
}
}
return winner;
}
然后我调用?降序=true&group=true&group_level=2从每个流中获取第一条消息,但是,它似乎不是按时间排序的,而是按所有者和stream_id排序的,像这样
{"rows":[
{"key":["sam","a"],
"value":
{"owner":"sam","stream_id":"a","timestamp":1303754236482,"message":"foo"}
},
{"key":["sam","b"],
"value":
{"owner":"sam","stream_id":"b","timestamp":1303752578476,"message":"bar"}
},
{"key":["jim","j1"],
"value":
{"owner":"jim","stream_id":"j1","timestamp":1303625378839,"message":"stuff"}
},
{"key":["bob","loblaw"],
"value":
{"owner":"bob","stream_id":"loblaw","timestamp":1303328396532,"message":"more stuff"}
},
{"key":["anthony","foo"],
"value":
{"owner":"anthony","stream_id":"foo","timestamp":1303769699444,"message":"even more"}
}
]}
(注意最后一项实际上是最近的时间)。
所以我想让最后的视图是现在的样子,但按时间排序。有办法做到这一点吗?
在每条消息中存储stream_created_at时间戳。对于第一条消息,取当前时间。对于流中的每个下一个消息,您可以从前一个消息复制它(为此创建一个视图以获取stream_created_at_by_stream_id)。
然后创建发出:
的视图[doc.owner,doc.stream_created_at, doc.stream_id, doc.receipt_time]
将来自同一流的消息分组在一起,同时保持时间顺序。流。当同时创建两个流时,Id将确保来自不同流的消息不会混淆。receipt_time将按时间对流中的消息排序。
所以最后你会得到类似Facebook的对话。而且你根本不需要任何reduce函数
如果我理解正确的话,您不是要过滤事件集合,而是要对它们进行排序。假设这是正确的,解决方案实际上很简单,你甚至不需要一个简化函数。在map函数中发出的键用于对视图进行排序,首先按键中的第一个排序,然后依次进行排序。换句话说,如果您希望按stream_id然后按receipt_time排序,那么您对emit的调用将看起来像这样:
emit([doc.stream_id,doc.receipt_time,doc.owner], doc.message);
自然地,如果你想按receipt_time然后按stream_id排序,键将改为[doc.receipt_time,doc.stream_id,doc.owner]
。我认为没有必要在键中包含任何已经存在的值,这就是为什么我将值缩减到只包含消息的原因。
我认为最简单的方法就是避免这个问题。
由于我控制发送事件的软件,我只是在流中的第一个文档中添加了一个"start":true,
字段,然后视图函数只发出具有该值的事件。
这意味着我不能获得历史数据,但这没关系,因为这主要用于检查最近的流。
我尝试的另一种选择是添加一个列表函数,它发送每个所有者stream_id的第一个实例,在一个视图的关键是[timestamp,owner,stream_id],然而,这遇到的问题是,当你限制它不限制最终渲染列表,但原始视图,所以额外的关键工作最好到目前为止)。
我仍然想知道是否有一些方法可以做到这一点与原始数据。