2
votes

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.

2
My answer to this question was broken. I'm sorry. I have updated it, please have another look.Marcello Nuccio
I am trying to understand your question. I edited it to show the expected output. Is my understanding correct? If so, I'll write up an answer. Thanks.JasonSmith
@jhs, yes this is correct. Thanks for making it more clear.stand
@jhs: Any further ideas about this? I'm still stumped.stand

2 Answers

1
votes

I think for this, ou need to construct your views not only with maps, but also with reduces.

0
votes

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