I am trying to implement a feature which requires a counter to be added in a document with initial value as 0. Now when I increment the counter value using the service, I want this counter value to get decremented 24hours later. In the mean time if I increment the counter value again then, 24 hours later this value should be decremented. The previous incremental value should also be decremented after its 24 hours is completed. so basically as soon as a value is incremented it should be there for24 hours and then it should be decremented, irrespective of how many increments are being done after tha.
Is there a way where I increment the counter in a document and after that incrementation the value in the document gets decremented after 24 hours automatically?
Have you looked at Eventing timers? I haven’t used them myself, but they seem like one way to schedule delayed code execution.
Another crazy idea would be that when you increment the counter, you also create a separate document with a unique key and a TTL of 24 hours. The key would identify the counter you want to decrement when the document expires. Couple this with an Eventing function that listens for document expiration and decrements the counter.
I can’t wholeheartedly recommend doing that though, because:
- Expiry notifications won’t happen immediately, since documents don’t expire util they are noticed y the expiry pager (I think it runs every 60 minutes by default).
- This isn’t robust, since a failure at any point could cause the counter to get out of sync. (Oooh, maybe instead of a single integer counter, you could use a N1QL query to count the number of “increment documents” (create a new document and the count goes up; A document expires and the count goes down)
What should you do instead? That probably depends on the actual problem you’re trying to solve. If you can describe in more detail why you want this kind of counter behavior, maybe we can suggest a more practical solution.
First of all Thanks for replying. Actually the use case I am trying to work on is that of email throttling where we are trying to restrict a user to send only 50 emails per day. Each email is saved in the document in couchbase. We were planning of creating a document which would have a counter for each user. Now, as soon as a user sends an email we would like to increment the counter. Now after 24 hours this counter for that user should be auto decremented. In that period if another email is sent then the counter decrement action for that increment should be done 24 hours after that.
Thanks for the background information. I’ll share a couple more ideas.
You could include a timestamp field to your email documents and use a N1QL query to see how many have been sent in the past 24 hours. See N1QL date functions and Querying Date Ranges within Embedded JSON Document Arrays. This won’t strictly enforce the limit, since there’s a race condidion between counting the emails and sending the new one.
Second idea (my personal favorite): For each user, have a document that contains an array of timestamps from when each email was sent. To see if user can send an email, read the document (and remember the CAS value so you can update the document atomically in just a bit). Read the list of timestamps and remove any that are more than 24 hours old. Count the remaining timestamps (if >= 50, sorry, can’t send email). Add the new timestamp to the list and write the document back to couchbase (using the same CAS value as when you read it, to guarantee that nobody else modified the document in the mean time. If there’s a CAS mismatch, start over by reading the document again).
Hey david Thanks alot man… You gave a new perspective to this problem which makes more sense now. Would discuss it with the team and see how they feel about this approach but I am really impressed by your favourite solution. Once again thanks alot😊
As David indicated this can also be done via Eventing I invite you to look as another Eventing specific forum post where I posted some code that uses Evening to create a “poor man’s crontab” explaind in the post “How to schedule a query in couchbase to run daily”
In the other posts example just replace the code block
// ========================================================= /* BEG ANYTHING YOU WANT HERE (pre 6.5 you have KV ops, for 6.5+ also N1QL AND CURL) will show N1QL */ // decrement once a day, make sure // 1 the BUCKET *mybucket* is aliased as RW in the Eventing function Setup screen (in 6.5+ this can be the src bucket) // 2 *some_fixed_key* is the 'id' to retrieve the document that has a field you are incrementing and decrementing. // where the document has a field say 'mycounter' that you want to decrement once daily. Not this 'id' is not from // the mutation of the timer but form the document you want to actually manipulate. var wrk = mybucket[some_fixed_key]; wrk.mycounter --; wrk[some_fixed_key] = wrk; /* END ANYTHING YOU WANT HERE */ // =========================================================