Note
While every design function has access to all JavaScript objects, the table below describes appropriate usage cases. For example, you may use emit() in List functions, but getRow() is not permitted during Map functions.
JS Function | Reasonable to use in design doc functions |
---|---|
emit() | Map functions |
getRow() | List functions |
JSON | any |
isArray() | any |
log() | any |
provides() | Show functions, List functions |
registerType() | Show functions, List functions |
require() | every except Reduce and rereduce functions |
send() | List functions |
start() | List functions |
sum() | any |
toJSON() | any |
Each design function executes within special context of predefined objects, modules and functions:
Puts key-value pair into inner stack for further passing to CouchDB when map function is done.
Arguments: |
|
---|
function(doc){
emit(doc._id, doc._rev);
}
Extracts next row from the related view result.
Returns: | View result row |
---|---|
Return type: | object |
function(head, req){
send('[');
row = getRow();
if (row){
send(toJSON(row));
while(row = getRow()){
send(',');
send(toJSON(row));
}
}
return ']';
}
Helper to check is provided value array or not
Arguments: |
|
---|---|
Returns: | true is obj is array typed, false otherwise. |
Return type: | boolean |
Arguments: |
|
---|
function(doc){
log('Procesing doc ' + doc['_id']);
emit(doc['_id'], null);
}
On map function run in CouchDB logs (e.g. at /var/log/couchdb/couch.log) you may find next record:
[Sat, 03 Nov 2012 17:38:02 GMT] [info] [<0.7543.0>] OS Process #Port<0.3289> Log :: Processing doc 8d300b86622d67953d102165dbe99467
Registers callable handler for specified MIME key.
Arguments: |
|
---|
Registers list of MIME types by associated key.
Arguments: |
|
---|
Predefined mappings (key-array):
Loads CommonJS module by specified path. Path shouldn’t starts with slash.
Arguments: |
|
---|---|
Returns: | Exported statements. |
Sends a single string chunk in response.
Arguments: |
|
---|
function(head, req){
send('Hello,');
send(' ');
send('Couch');
return !
}
Initiates chunked response. As an option, custom response object may be sent at this point. For list-functions only!
Note
Only at this point list functions may set response HTTP code and headers. Also, you need to run this function before send(), getRow() or return statement or query server will implicitly call this function with empty object ({}).
function(head, req){
start({
"code": 302,
"headers": {
"Location": "http://couchdb.apache.org"
}
});
return "Relax!";
}
Summarize arr items.
Arguments: |
|
---|---|
Return type: | number |
Encodes obj to JSON string. Actually is a proxy to JSON.stringify method.
Arguments: |
|
---|---|
Returns: | JSON string. |
CommonJS Modules is the one of major CouchDB feature introduced in 0.11.0 version that allows to create modular design functions without needs to duplicate a lot of same functionality.
Example of CommonJS module that checks user permissions:
function user_context(userctx, secobj){
var is_admin = function(){
return userctx.indexOf('_admin') != -1;
}
var is_db_admin = function(){
if (is_admin() || !secobj){
return true;
}
if (secobj.admins.names.indexOf(userctx.name) != -1){
return true;
}
for (var idx in userctx.roles){
if (secobj.admins.roles.indexOf(userctx.roles[idx]) != -1){
return true;
}
}
return false;
}
var is_db_member = function(){
if (is_admin() || is_db_admin() || !secobj){
return true;
}
if (secobj.members.names.indexOf(userctx.name) != -1){
return true;
}
for (var idx in userctx.roles){
if (secobj.members.roles.indexOf(userctx.roles[idx]) != -1){
return true;
}
}
return false;
}
var has_all_roles = function(roles){
for (var idx in roles){
if (userctx.roles.indexOf(roles[idx]) == -1){
return false;
}
}
return true;
}
var has_any_role = function(roles){
for (var idx in roles){
if (userctx.roles.indexOf(roles[idx]) != -1){
return true;
}
}
return false;
}
return {
'is_admin': is_admin,
'is_db_admin': is_db_admin,
'is_db_member': is_db_member,
'has_all_roles': has_all_roles,
'has_any_role': has_any_role
}
}
exports['user'] = user_context
Each module has access to additional global variables:
Lets place module above within design document under lib/validate path. Now we could use it in our design functions:
function(newdoc, olddoc, userctx, secobj){
user = require('lib/validate').user(userctx, secobj);
if (user.is_admin()){
return true;
}
if (newdoc.author != olddoc.author){
throw({'forbidden': 'unable to update `author` field'});
}
}
Warning
Erlang query server runs out of sandbox feature like JavaScript has to! This means, that Erlang code has full access to your OS, file system and network which may leads to security issues. While Erlang functions are faster than JavaScript ones, you need to be careful with running them, especially if they wasn’t written by your own hands.
Keep in mind: don’t trust every code - review it first before running.
Note
Due to security restriction, Erlang query server is disabled by default. To enable it you’ll need to edit your local.ini to include a native_query_servers section:
[native_query_servers]
erlang = {couch_native_process, start_link, []}
And don’t forget to restart CouchDB after that and use language: "erlang" property in your Erlang design documents.
Emits key-value pair to view indexer process.
fun({Doc}) ->
<<K,_/binary>> = proplists:get_value(<<"_rev">>, Doc, null),
V = proplists:get_value(<<"_id">>, Doc, null),
Emit(<<K>>, V)
end.
Helper to iterate over all rows in list function.
Arguments: |
|
---|
fun(Head, {Req}) ->
Fun = fun({Row}, Acc) ->
Id = couch_util:get_value(<<"id">>, Row),
Send(list_to_binary(io_lib:format("Previous doc id: ~p~n", [Acc]))),
Send(list_to_binary(io_lib:format("Current doc id: ~p~n", [Id]))),
{ok, Id}
end,
FoldRows(Fun, nil),
""
end.
Retrieves next row from related view result.
%% FoldRows background implementation.
%% https://git-wip-us.apache.org/repos/asf?p=couchdb.git;a=blob;f=src/couchdb/couch_native_process.erl;hb=HEAD#l368
%%
foldrows(GetRow, ProcRow, Acc) ->
case GetRow() of
nil ->
{ok, Acc};
Row ->
case (catch ProcRow(Row, Acc)) of
{ok, Acc2} ->
foldrows(GetRow, ProcRow, Acc2);
{stop, Acc2} ->
{ok, Acc2}
end
end.
Arguments: |
|
---|
fun({Doc}) ->
<<K,_/binary>> = proplists:get_value(<<"_rev">>, Doc, null),
V = proplists:get_value(<<"_id">>, Doc, null),
Log(lists:flatten(io_lib:format("Hello from ~s doc!", [V]))),
Emit(<<K>>, V)
end.
On map function run in CouchDB logs (e.g. at /var/log/couchdb/couch.log) you may find next record:
[Sun, 04 Nov 2012 11:33:58 GMT] [info] [<0.9144.2>] Hello from 8d300b86622d67953d102165dbe99467 doc!
Sends a single string Chunk in response.
fun(Head, {Req}) ->
Send("Hello,"),
Send(" "),
Send("Couch"),
"!"
end.
Function above produces next response:
Hello, Couch!
Arguments: |
|
---|
Initialize List functions response. At this point response code and headers may be defined. For example, next function redirect to CouchDB web site:
fun(Head, {Req}) ->
Start({[{<<"code">>, 302},
{<<"headers">>, {[
{<<"Location">>, <<"http://couchdb.apache.org">>}]
}}
]}),
"Relax!"
end.