kpavel
kpavel

Reputation: 282

CouchDB filter function and continuous feed

I have a filter function filtering based on document property, e.g. "version: A" and it works fine, until there a document update at some point in time when this property "version: A" removed (or updated to "version: B").

At this point i would like to be notified that the document been updated, similar to one when the document get deleted, but couldn't find an effective way (without listening and processing all documents changes).

Hope i'm just missing something and it's not a design limitation.

Upvotes: 0

Views: 1471

Answers (3)

Daniel Paull
Daniel Paull

Reputation: 6843

While my other answer is a valid approach, I had this same situation yesterday and decided to look at making this work using Mango selectors. I did the following:

  1. Establish a changes feed filtered by the query selector (see the "_selector" filter for /db/_changes)
  2. Perform the query (db/_find) and record the results
  3. Establish a second changes feed that filters for just in the documents returned in (2) (see the "_doc_ids" filter for /db/_changes)

The feed at (1) lets you know when new documents match your query along with edits to documents that matched your query both before and after the change.

The feed at (2) lets you know when a change is made to a document that previously matched your query, irrespective of if it matches your query after the change has been made.

The combination of these feeds covers all cases, though with some false positives. On a change in either feed, tear down the changes feed at (3) and redo steps (2) and (3).

Now, some notes on this approach:

  • This is really only suitable in cases where the number of documents returned by the query is small because if the filtering by _id in the second feed.
  • Care must be taken to ensure that the second feed is established correctly if there are lots of changes coming in from the first changes feed.
  • There are cases where a change will appear in both feeds. It would be good to avoid reacting twice.
  • If changes are expected to happen frequently, then employ debouncing or rate limiting if your client does not need to process each and every change notification.

This approach worked well for me and the cases I had to deal with.

References:

Upvotes: 2

Daniel Paull
Daniel Paull

Reputation: 6843

The closest you will come to this is to use a view and filter the changes feed based on that view - see [1] for details.

You can create a simple view that includes the "version" as part of the key using a map function such as:

function (doc) {
  emit(doc.version, 1);
}

A changes feed filtered by this view will notify you of the insert or deletion of documents that have a "version" field as well as changes to the "version" field of existing documents. You can not, however, determine the previous value of the "version" field from the changes feed.

Depending on your requirements, you can make the view more targeted. For example, if you only cared about transition form "A" to "B" then you could include only documents that have "A" or "B" as their "Version":

function (doc) {
  if( doc.version === "A" || doc.version === "B") {
    emit(doc.version, 1);
  }
}

But be aware that this will not trigger a change notification on transition from, say, "A" to "C" (or any other value for "version", including when the document is deleted) because change notifications are only send when the map function emit()'s at least one value for a document. It doesn't not notify you when the map function used to emit at least one value for a give document, but no longer does!

You can also filter the changes feed using Mango selectors, so if Mango queries work for you then perhaps this is simpler than using a view, but I'm not sure that you can be notified of deletions via Mango selectors...

EDIT:

May claim about the simple map function above is not quite right as it will notify you of all document insertions and deletions, not just ones with a "version" field. You can do this to avoid some of those false positive notifications:

function (doc) {
  if ( doc.hasOwnProperty( 'version' ) || doc.hasOwnProperty( '_deleted' ) ) {
    emit(doc.version, 1);
  }
}

That will give notifications for new documents with a "version" field, or an update that adds a "version" field to an existing document, but it will still notify of all deletions.

[1] http://docs.couchdb.org/en/stable/api/database/changes.html#changes-filter-view

Upvotes: 0

Juanjo Rodriguez
Juanjo Rodriguez

Reputation: 2131

The behaviour that you described is correct.

CouchDB will populate the changes feed with the docs that accomplish with the filter function. If you remove/modify the information that is used by the filter function the filtered changes feed will ignore those updates.

Upvotes: 0

Related Questions