How do I DRY up my CouchDB views?
Asked Answered
M

5

18

What can I do to share code among views in CouchDB?

Example 1 -- utility methods

Jesse Hallett has some good utility methods, including

function dot(attr) {
  return function(obj) {
      return obj[attr];
  }
}

Array.prototype.map = function(func) {
  var i, r = [],
  for (i = 0; i < this.length; i += 1) {
    r[i] = func(this[i]);
  }
  return r;
};

...

Where can I put this code so every view can access it?

Example 2 -- constants

Similarly for constants I use in my application. Where do I put

MyApp = {
  A_CONSTANT = "...";
  ANOTHER_CONSTANT = "...";
};

Example 3 -- filter of a filter:

What if I want a one view that filters by "is this a rich person?":

function(doc) {
  if (doc.type == 'person' && doc.net_worth > 1000000) {
    emit(doc.id, doc);
  }
}

and another that indexes by last name:

function(doc) {
  if (doc.last_name) {
    emit(doc.last_name, doc);
  }
}

How can I combine them into a "rich people by last name" view?

I sort of want the equivalent of the Ruby

my_array.select { |x| x.person? }.select { |x| x.net_worth > 1,000,000 }.map { |x| [x.last_name, x] }

How can I be DRYer?

Mikesell answered 29/7, 2009 at 0:16 Comment(1)
Apparently there are "no development plans to share code/functions between views." See wiki.apache.org/couchdb/HTTP_view_API#view_share_code But that doesn't answer my question about filters of filters or maps of filters, etc.Mikesell
L
3

The answer lies in couchapp. With couchapp you can embed macros that include common library code into any of the design document sections. It is done before the design document is submitted to the server. What you need to do to do the query you ask about is reverse the keys that are emitted so you can do a range query on the "network"

function(doc) 
{
  if (doc.type == 'person') 
  {
    emit([doc.net_worth, doc.lastname], null);
  }
}

You don't want to include the doc you can do that with include_docs=true on the query parameters. And you get the doc.id for free as part of the key. Now you can do a range query on networth which would look something like this.

http://localhost:5984/database/_design/people/_view/by_net_worth?startkey=[1000000]&endkey=[{},{}]&include_docs=true
Leeway answered 20/4, 2010 at 4:0 Comment(0)
M
23

As per this blog post, you can add commonjs modules to the map function (but not the reduce function) in views in couchdb 1.1 by having a key called lib in your views object. A lot of popular javascript libraries like underscore.js adhere to the commonjs standard, so you can use them in your views by using require("views/lib/[your module name]").

Say you include underscore.js as "underscore" in the lib object in views, like so:

views: {
    lib: {
         underscore: "// Underscore.js 1.1.6\n ...
    }
    ...
    [ the rest of your views go here]
}

, you can then add the following to your view to get access to the _ module:

var _ = require("views/lib/underscore");

For custom libraries, all you need to do is make anything you want to share in your library a value to the global "exports" object.

Milepost answered 11/10, 2011 at 14:51 Comment(1)
Excellent article you refer to, thx ;) -- should be the answerAuthority
N
8

From the CouchDB Wiki:

There are no development plans to share code/functions between views. Each view function is stored according to a hash of their byte representation, so it is important that a function does not load any additional code, changing its behavior without changing its byte-string. Hence the use-case for CouchApp.

Nigrescent answered 29/7, 2009 at 1:38 Comment(2)
This information was correct, but it seems that it is outdated in our days.Cinerarium
@Antonio Can you provide any references to how to do it using the current CouchDB rel? (ie: 1.6 or greater?)Refugia
L
3

The answer lies in couchapp. With couchapp you can embed macros that include common library code into any of the design document sections. It is done before the design document is submitted to the server. What you need to do to do the query you ask about is reverse the keys that are emitted so you can do a range query on the "network"

function(doc) 
{
  if (doc.type == 'person') 
  {
    emit([doc.net_worth, doc.lastname], null);
  }
}

You don't want to include the doc you can do that with include_docs=true on the query parameters. And you get the doc.id for free as part of the key. Now you can do a range query on networth which would look something like this.

http://localhost:5984/database/_design/people/_view/by_net_worth?startkey=[1000000]&endkey=[{},{}]&include_docs=true
Leeway answered 20/4, 2010 at 4:0 Comment(0)
P
1

Couchapp will "macro" in libraries, and it works pretty well.

The other, unsupported option is to add utility functions like that to a custom query server. The JS file is not that difficult to understand, and the Ruby and Python versions are even simpler. The view server compiles the strings in the design doc into function objects as they are executed, so if you close those functions over utility functions, constants or whatever, they'll be executable in map/reduce/show/list functions.

Look for the place in the main.js file where "emit" and "log" are defined, and emulate the definition of those functions to expose your custom utility functions to your map and reduce lambdas.

Caveat: Changing the view server without requiring a rebuild on your view will mean that your view index will not be correct. Programmer Beware.

Psychasthenia answered 13/7, 2010 at 3:17 Comment(0)
B
-2

You can't do this (last I checked) because the views are stored in the database, and the key for the view is a hash of itself. A view cannot rely on outside data/logic/programming, because if it changes then the view is different and won't match. It confused me, and still does, so I may be wrong.

Browse answered 29/7, 2009 at 1:26 Comment(1)
Since couchdb has to update the indexes when a view changes it needs to know when the view has changed. If you rely on external libraries or code in the view then the view can change without couchdb's knowledge. This will cause the index to be stale and possibly incorrect. That being said you could theoretically create your own javascript view server that bundles the libraries with the caveat and risks noted above.Disinherit

© 2022 - 2024 — McMap. All rights reserved.