1

I have set of docs in my couchdb here I mentioned one sample doc:

{
"_id": "26",
"_rev": "1-53ac67e9ec4b4ce8ffa9cd609e107aaf",
 "customer_name": "Vadilal",
"type": "trip",
"duration": "10 hours 27 mins",
"end_time": "Jan 1, 2014 10:11:00 PM",
"start_time": "Jan 11, 2014 8:46:00 AM",
}

If I pass timestamp(key) from the URL, if it is in between start_time and end_time then i want to get the docs.

Example:

suppose url would be like this

   .../trip/_design/trip/_view/trip?key="Jan 10, 2014 8:46:00 AM"

Here I am passing timestamp as Jan 10, 2014 8:46:00 AM so it comes in between start_time and end_time of above mentioned doc, in this case I need fetch the remaining information.

Kindly help to figure out this problem, it would be great help to me.

I have written function like below :

    function(doc){
    if(doc.type=="trip"){ 
   var startTime=new Date(doc.start_time);
   var endTime=new Date(doc.end_time);
  emit([startTime.getTime(),endTime.getTime()], doc);
    }

And calling URL as below :

../trip/_design/trip/_view/trip?startkey=[1390086890000]&endkey=[1390086890000,{}]

is above one correct according to my requirement???

1 Answers1

4

That is unfortunately not possible. There are two problems with you requirement.

Views are arranged by a key

You could write a view like this to index documents by the start key or the end key respectively.

    function(doc){
      emit(doc.start_time, doc_id); // amend with end key to index by end key.
    }

you can use three parameters in your query:

  • key - matches an exact key
  • startkey - matches all documents that are greater or equal to the start key
  • endkey - matches all documents that are greater or equal to the end key

The sorting problem

Depending on the type your index keys will be sorted either alphabetically or as integers. So if your view trip is using a start key like this:

    .../trip/_design/trip/_view/trip?start_key="Jan 10, 2014 8:46:00 AM"

You could return all values greater or equal to the string "Jan 10, 2014..." which would be true for "Jan 11, 2014" or "Jan 31, 2014" but there would be false positives for "July 22, 2011" or false negatives for "Feb 01, 2014" as F < J.

To solve this issue you will have to convert the start date to something that can be sorted in time order eg:

Both of these will sort correctly.

Can you solve your problem

Yes, but with a little client side code. Here's the recipe:

  • create two views trip/by_start_date and trip/by_end_date which return the start and end date as keys respectively. In a way that is sorted as per the second section above.
  • Get two sets of documents.
  • Set 1 should return all documents that start before your date: ..._view/by_start_date?endkey=[your_date]
  • set 2 should return all documents that end after your date: ..._view/by_end_date?startkey=[your_date]
  • You then have two sets of document ids and the result you were after will be those documents that are in both these sets.

Further optimization

In the above solution you might just get too many values returned to handle. You can further cut it down using CouchDB's ability to key on more than one value. Key by both start and end date like this:

    function(doc){
      var start_time = some_conversion_function(doc.start_time);
      var end_time = some_conversion_function(doc.end_time);
      emit([start_time, end_time], doc_id);
    }

If you have any more details on the maximum difference between start time and end time you can use this to further reduce the documents in each set. The below example will return the documents that start no later than X days before date and no later than date and end no later than X days after date.

    ..._view/by_start_date?startkey=[date-X,]&endkey=[date, date+X]

You can apply a similar logic to the by_end_date view.

Community
  • 1
  • 1
Hans
  • 2,800
  • 3
  • 28
  • 40
  • I have written function like below : function(doc){ if(doc.type=="trip"){ var startTime=new Date(doc.start_time); var endTime=new Date(doc.end_time); emit([startTime.getTime(),endTime.getTime()], doc); } And calling URL as below : ../trip/_design/trip/_view/trip?startkey=[1390086890000]&endkey=[1390086890000,{}] is above one correct according to my requirement??? – Praneeth Vadlakonda May 07 '14 at 06:56
  • Sorting by epoch is correct and good. Instead of one view, I believe you'll have to use two queries and get a list of documents (I'd only return the `doc._id` not the complete document. You then have two lists, one of all doc._id's starting before your date and one with all your doc._id's ending after your date. Intersect these two lists to find those docs starting before and ending after your date. This is what I explained in section 'Can you solve the problem'. – Hans May 07 '14 at 07:07
  • I have created two views by_start_date and by_end_date. And calling two views like http://localhost:5984/trip/_design/by_start_date/_view/by_start_date?endkey=[15677878890000] http://localhost:5984/trip/_design/by_end_date/_view/by_end_date?startkey=[1390086890000] but how can I get the records according my requirement. – Praneeth Vadlakonda May 08 '14 at 11:09
  • In your client code get the doc._id of the views and place them in an array. Then get the intersections of the two. I don't think you've mentioned your client language, but if it's javascript then this could help: http://stackoverflow.com/questions/1885557/simplest-code-for-array-intersection-in-javascript if it's python try: http://stackoverflow.com/questions/642763/python-intersection-of-two-lists – Hans May 08 '14 at 12:46
  • I got u but my requirement is when client calls the URL by passing timestamp as the key then I have to compare that timestamp with start_time and end_time, if key lies between start and end time then only I have to send the docs. – Praneeth Vadlakonda May 08 '14 at 13:01
  • And here I have to give only one URL to the client not two. – Praneeth Vadlakonda May 08 '14 at 13:02
  • I don't think what you want is possible, however if you were to write a simple api yourself (eg using the nodejs express framework) you can take the key as the parameter, call couchdb and do the intersect within the API. – Hans May 08 '14 at 13:14