我正在使用CouchDB。我希望能够计算在查询时指定的日期范围内特定字段值的出现次数。我似乎能够做到这一部分,但我无法理解将它们全部拉到一起的最佳方式。
假设文档具有时间戳字段和另一个字段,例如:
{ date: '20120101-1853', author: 'bart' }
{ date: '20120102-1850', author: 'homer'}
{ date: '20120103-2359', author: 'homer'}
{ date: '20120104-1200', author: 'lisa'}
{ date: '20120815-1250', author: 'lisa'}
我可以轻松创建按灵活日期范围过滤文档的视图。这可以通过下面的视图来完成,使用关键范围参数调用,例如, _view/all-docs?startkey=20120101-0000&endkey=20120201-0000
。
全文档/ map.js:
function(doc) {
emit(doc.date, doc);
}
根据上面的数据,这将返回一个仅包含前4个文档的CouchDB视图(日期范围内的唯一文档)。
我还可以创建一个计算给定字段的出现次数的查询,就像这样,通过分组调用,即_view/author-count?group=true
:
作者计数/ map.js:
function(doc) {
emit(doc.author, 1);
}
作者计数/ reduce.js:
function(keys, values, rereduce) {
return sum(values);
}
这会产生类似的结果:
{
"rows": [
{"key":"bart","value":1},
{"key":"homer","value":2}
{"key":"lisa","value":2}
]
}
但是,我找不到按日期过滤和计算出现次数的最佳方法。例如,根据上面的数据,我希望能够指定范围参数,例如startkey=20120101-0000&endkey=20120201-0000
,并得到这样的结果,其中最后一个文档从计数中排除,因为它超出了指定的日期范围:
{
"rows": [
{"key":"bart","value":1},
{"key":"homer","value":2}
{"key":"lisa","value":1}
]
}
最优雅的方法是什么?这可以通过单个查询实现吗?我应该使用另一个CouchDB构造,还是一个足够的视图?
答案 0 :(得分:2)
您可以使用列表非常接近所需的结果:
{
_id: "_design/authors",
views: {
authors_by_date: {
map: function(doc) {
emit(doc.date, doc.author);
}
}
},
lists: {
count_occurrences: function(head, req) {
start({ headers: { "Content-Type": "application/json" }});
var result = {};
var row;
while(row = getRow()) {
var val = row.value;
if(result[val]) result[val]++;
else result[val] = 1;
}
return result;
}
}
}
这样的设计可以这样要求:
http://<couchurl>/<db>/_design/authors/_list/count_occurrences/authors_by_date?startkey=<startDate>&endkey=<endDate>
这比普通的map-reduce慢,并且有点变通方法。不幸的是,这是进行多维查询的唯一方法"which CouchDB isn’t suited for"。
请求此设计的结果将是这样的:
{
"bart": 1,
"homer": 2,
"lisa": 2
}
我们所做的基本上是发出很多元素,然后使用列表按照我们的意愿对它们进行分组。列表可用于以您想要的任何方式显示结果,但通常也会较慢。虽然可以缓存普通的map-reduce并且只根据差异进行更改,但每次请求时都必须重新构建列表。
它几乎与获取地图产生的所有元素一样慢(编排数据的开销几乎可以忽略不计):比获得减少的结果慢得多。
如果您想将该列表用于其他视图,只需在您请求的网址中进行交换即可:
http://<couchurl>/<db>/_design/authors/_list/count_occurrences/<view>
答案 1 :(得分:0)
您需要创建组合视图:
组合/ map.js:
function(doc) {
emit([doc.date, doc.author], 1);
}
组合/ reduce.js:
_sum
这样您就可以按开始/结束日期过滤文档。
startkey=[20120101-0000, "a"]&endkey=[20120201-0000, "a"]
答案 2 :(得分:0)
虽然在一般情况下您的问题很难解决,但了解对可能的查询的更多限制可能会有很大帮助。例如。如果您知道将搜索将覆盖整天/月的范围,则可以使用[year, month, day, time]
的数组而不是字符串:
emit([doc.date_year, doc.date_month, doc.date_day, doc.date_time, doc.author] doc);
即使您无法预测所有可能的查询都适合基于此键类型的分组,拆分键可以帮助您优化范围查询并减少所需的查找次数(以及一些额外空间的成本)。 / p>