Skip to content
This repository has been archived by the owner on Oct 14, 2020. It is now read-only.

Being Notified About Changes

Lucas Satabin edited this page Apr 8, 2014 · 5 revisions

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)

Filtering Changes

Native CouchDB Filtering

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.

Sohva (Client-Side) Filtering

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.