Reputation: 3132
I have a couchdb database filled with time-stamped documents so the format of a given document is something like this:
{ id: "uniqueid",
year: 2011,
month: 3,
day: 31,
foo: "whatever"
bar: "something else"
}
I would like to construct a set of views such that a given key will return an array of year, month or day values for which documents exist. For example given the view name Days
, I would like the following view url
/db/_design/designdoc/_view/Days?key=[2011,3]
to return an array of all the days in March of 2011 for which documents exist. For example, if March 2011 had some number of documents falling on six days, it might look like:
[1, 2, 5, 15, 27, 31]
Similarly,
/db/_design/designdoc/_view/Months?key=2011
If 2011 had some number of documents falling on April, May, and September, it might look like:
[4, 5, 9]
And
/db/_design/designdoc/_view/Years
will return an array of years in the whole database. If the documents have this year and last, it might look like:
[2010, 2011]
I gather it is difficult to write a reduce function that returns an array because you end up running into reduce overflow errors as the document count increases. I know this because I wrote a reduce function that worked but then started throwing reduce overflow errors after I loaded it up with documents.
One solution I have examined is just creating a view without a reduce that creates an array key [year, month, day]
and then using startkey
and endkey
parameters on the view to return documents. The problem with this approach is how it scales. Say my database has thousands of documents spread out over two years. Using this view, I need to iterate over the entire set of documents just to discover this.
I believe this question is trying to ask the same thing though I am not quite sure so I figured I'd add a new question. Also, the answers given on that question do not avoid reduce overflow errors for larger document sets, as far as I could tell with my limited view writing skills.
Upvotes: 2
Views: 1882
Reputation: 1983
Disregarding eventual scaling problems there are 2 solutions. I will take into account only Days since the answer for Months and Years is similar.
Solution 1:
view Days:
map:
function(doc) {
if (doc.year && doc. month && doc.day) {
emit([ year, month, day ], 1);
}
}
reduce:
function(keys, values) {
return sum(values);
}
list listDays:
function(head, req) {
start({
"headers": {
"Content-Type": "text/plain"
}
});
var row;
var days = new Array();
while(row = getRow()) {
days.push(row.key[2]);
}
var daysString = json.join(',');
send('[' + daysString + ']');
}
http call:
http://couch/db/_design/db/_list/listDays/Days?group=true&group_level=2&startkey=["2011","3"]&endkey=["2011","3Z"]
Solution 2:
view Days:
map:
function(doc) {
if (doc.year && doc. month && doc.day) {
emit([ year, month, day ], null);
}
}
list listDays:
function(head, req) {
start({
"headers": {
"Content-Type": "text/plain"
}
});
var row;
var days = new Array();
while(row = getRow()) {
if (days.indexOf(row.key[2] == -1) { days.push(row.key[2]); }
}
var daysString = json.join(',');
send('[' + daysString + ']');
}
http call:
http://couch/db/_design/db/_list/listDays/Days?startkey=["2011","3"]&endkey=["2011","3Z"]
Upvotes: 0
Reputation: 3367
I think for this, ou need to construct your views not only with maps, but also with reduces.
Upvotes: 1