-
-
Notifications
You must be signed in to change notification settings - Fork 7
Being Notified About Changes
This page is obsolete: Starting with version 1.0.0, the change stream is implemented as an Observable
and is no longer implemented with some sort of degenerated API.
CouchDB exposes an API that allows clients to be notified about any change in near real-time. Sohva is now able to register handlers that are called whenever a change occurs in a database.
The Database
class has a changes
method that returns a ChangeStream
. This method takes an optional filter name, so that one can use the filter mechanism of CouchDB to get only relevant changes.
The ChangeStream
class is the base class to register new handlers to and unregister handlers from this change stream. Using the foreach
method, one can subscribe to the changes and get notified about them. Always remember that theses handlers are called synchronously, so if any blocking task is performed in one handler, one should take care to execute it asynchronously.
When a document is added or modified in the database, the handler gets its identifier together with the new document as raw Json object. When the document was deleted, only the identifier is passed to the handler.
This is a pretty low-level API which involves working with the untyped Json documents.
Practically, you can use it this way:
val couch = new CouchClient
val db = couch.database("test")
val changes = db.changes()
// foreach change execute something
val handler1 = changes.foreach {
case (id, doc) => // do something
}
// which is equivalent to
val handler2 = for((id, doc) <- changes) {
// do something
}
// one can dynamically unregister handlers
changes.unregister(handler1)
changes.unregister(handler2)
CouchDB provides filtering on the server side. it is possible to register filter functions in design documents that may be referred to when subscribing to a database change stream.
In Sohva, you may given the name of the filter when subscribing to the changes stream
val changes = db.changes("design-name/filter-name")
This works if you have a design _design/design-name
which contains a filter function named filter-name
in your database. For more details, see the CouchDB guide.
Let's say your client registers several handlers, each of which needs different filtering. You could of course subscribe several times to the changes channel of the database, specifying a different filter function for each subscription. That's good, but it means that you open as many connections to the database as handlers. That may not be optimal. Sohva uses the special for-comprehension syntax to allow people to define client-side filters in a convenient way.
For example, one can write:
// open the changes stream without filtering
val changes = db.changes()
// do something for all changes
for((id, doc) <- changes) { ... }
// do something for deleted documents only
for((id, None) <- changes) { ... }
// do something depending on a predicate on the id only
for {
(id, doc) <- changes
if p(id)
} {
...
}
...
This opens only one connection to the database, the filtering being done on the client side.