Couchdb River using Tire and CouchRest::Model

tmaier edited this page Dec 20, 2012 · 2 revisions

If you want to use the Couchdb river to keep your CouchRest::Models automatically indexed you need to install it

elasticsearch/bin/plugin -install river-couchdb

Now you're able to create your river using tire

  class Person < CouchRest::Model::Base
    include Tire::Model::Search
  end

  model = Person
  river_name = model.model_name.singular
  index_name = model.model_name.plural
  type_name  = model.model_name.singular
  db_name = CouchRest::Model::Base.database.name
  db_uri = URI.parse(CouchRest::Model::Base.database.to_s)

  river_payload = {
                   type: "couchdb",
                   couchdb: {
                     host: db_uri.host,
                     port: db_uri.port,
                     db: db_name,
                     filter: null
                   },
                   index: {
                        index: index_name,
                        type: type_name
                   }
  }
  
  Tire::Configuration.client.put("#{Tire::Configuration.url}/_river/#{river_name}/_meta", river_payload.to_json)
  Tire.index('_river').refresh

If you have more than one CouchRest::Model all of them are indexed in the same index due to the filter: null config option of the previous river. More Couchdb Filters

So we create the filter for our Person class (each Person doc has a key type with value 'Person')

curl -vX PUT 'http://127.0.0.1:5984/couchdb_name/_design/Person' -d '{
   "_id": "_design/Person",
   "language": "javascript",
   "filters": {
       "person": "function(doc, req) { return doc['type'] == 'Person'; }"
   }
}'

To create this filter inside your CouchRest::Model class you could use the following module

module CouchRest
  module Model

    module Elastic
      extend ActiveSupport::Concern

      module InstanceMethods
        # Create a new Elastic search method. Accepts the following options:
        #
        # * :filter_name   - the name of the _changes filter to be created.
        # * :filter_method - the actual method definition to use.
        #
        def elastic(opts = {})
          opts[:filter_name] ||= model.to_s
          opts[:filter_method] ||= "function(doc, req) { return doc['#{model.model_type_key}'] == '#{self.model.to_s}'; }"
          # Create a filter for this model
          filter(opts[:filter_name], opts[:filter_method])
        end
      end
    end
  end
end

CouchRest::Model::Designs::DesignMapper.send(:include, CouchRest::Model::Elastic)

class Person < CouchRest::Model::Base
  include Tire::Model::Search  

  design do
    elastic
  end
end