2010-03-10 23 views
10

CouchDB, versión 0.10.0, utilizando vistas de erlang nativas.Emitir Tuplas desde vistas de Erlang en CouchDB

Tengo un documento simple de la forma:

{ 
    "_id": "user-1", 
    "_rev": "1-9ccf63b66b62d15d75daa211c5a7fb0d", 
    "type": "user", 
    "identifiers": [ 
     "ABC", 
     "DEF", 
     "123" 
    ], 
    "username": "monkey", 
    "name": "Monkey Man" 
} 

Y un documento de diseño Javascript básica:

{ 
    "_id": "_design/user", 
    "_rev": "1-94bd8a0dbce5e2efd699d17acea1db0b", 
    "language": "javascript", 
    "views": { 
    "find_by_identifier": { 
     "map": "function(doc) { 
      if (doc.type == 'user') { 
      doc.identifiers.forEach(function(identifier) { 
       emit(identifier, {\"username\":doc.username,\"name\":doc.name}); 
      }); 
      } 
     }" 
    } 
    } 
} 

que emite:

{"total_rows":3,"offset":0,"rows":[ 
{"id":"user-1","key":"ABC","value":{"username":"monkey","name":"Monkey Man"}}, 
{"id":"user-1","key":"DEF","value":{"username":"monkey","name":"Monkey Man"}}, 
{"id":"user-1","key":"123","value":{"username":"monkey","name":"Monkey Man"}} 
]} 

Estoy buscando en la construcción una vista de Erlang que hace lo mismo. Mejor intento hasta ahora es:

%% Map Function 
fun({Doc}) -> 
    case proplists:get_value(<<"type">>, Doc) of 
    undefined -> 
     ok; 
    Type -> 
     Identifiers = proplists:get_value(<<"identifiers">>, Doc), 
     ID = proplists:get_value(<<"_id">>, Doc), 
     Username = proplists:get_value(<<"username">>, Doc), 
     Name = proplists:get_value(<<"name">>, Doc), 
     lists:foreach(fun(Identifier) -> Emit(Identifier, [ID, Username, Name]) end, Identifiers); 
    _ -> 
     ok 
    end 
end. 

que emite:

{"total_rows":3,"offset":0,"rows":[ 
{"id":"user-1","key":"ABC","value":["monkey","Monkey Man"]}, 
{"id":"user-1","key":"DEF","value":["monkey","Monkey Man"]}, 
{"id":"user-1","key":"123","value":["monkey","Monkey Man"]} 
]} 

La pregunta es - ¿Cómo puedo conseguir esos valores como tuplas, en lugar de como matrices? No me imagino que puedo (o me gustaría) usar registros, pero el uso de átomos en una tupla no parece funcionar.

lists:foreach(fun(Identifier) -> Emit(Identifier, {id, ID, username, Username, name, Name}) end, Identifiers); 

se produce el siguiente error:

{"error":"json_encode","reason":"{bad_term,{<<\"user-1\">>,<<\"monkey\">>,<<\"Monkey Man\">>}}"} 

Pensamientos? Sé que Erlang apesta por este tipo específico de cosas (acceso con nombre) y que puedo hacerlo por convención (identificación en primera posición, nombre de usuario siguiente, nombre real en último lugar), pero eso hace que el código del lado del cliente sea bastante feo.

+0

No conozco los detalles de CouchDB, así que no tengo idea de a qué función se refiere 'Emit', pero al parecer json_encode utilizado en CouchDB requiere una lista como entrada. Ver: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_util.erl?view=markup#l317 – Zed

+0

Emitir es la función que devuelve datos de la función de mapa para ser reducida más tarde. . Tiene un equivalente en la versión JS, y supongo que ambos están integrados en el mecanismo de vista CouchDB. Gracias por el enlace. Eso explica por qué no funciona. Ahora, para saber cómo solucionarlo :) – majelbstoat

+0

Sé lo que se emite en general; Simplemente no conozco la función referida por la variable 'Emit' en su código pegado. – Zed

Respuesta

13

El objeto JSON {"foo":"bar","baz":1} es {[{<<"foo">>,<<"bar">>},{<<"baz">>,1}]}

En Erlang Lingua es un proplist envuelto en una tupla.

No es bonita, pero muy eficiente :)

Para tener una idea de que se puede jugar con la lib JSON que se incluye con CouchDB:

  1. inicio CouchDB con la -i (interactivo) flag
  2. en la cáscara erlang resultante, tipo: couch_util:json_decode(<<"{\"foo\":\"bar\"}">>).
  3. Profit

// en versiones posteriores de CouchDB, esto es ejson:decode()

+0

¡Perfecto! Esto realmente ayudó :) – majelbstoat

+0

Al decodificar json que tiene claves anidadas, ¿hay que escapar de {con un \ {también? –

0

Si te gusta características experimentales (que todavía funcionan ...), es posible que desee echar un vistazo a Erlang exprecs.

Me pareció extremadamente útil crear un tipo de registros dinámicos para Erlang.

3

Para test_suite_reports bd, que tiene pruebas de campo:

[ 
    { 
     "name": "basics", 
     "status": "success", 
     "duration": 21795 
    }, 
    { 
     "name": "all_docs", 
     "status": "success", 
     "duration": 385 
    } ... 

he escrito esto para obtener el nombre y el estado:

fun({Doc}) -> 
    Name = fun(L) -> proplists:get_value(<<"name">>, L, null) end, 
    Status = fun(L) -> proplists:get_value(<<"status">>, L, null) end, 
    Tests = proplists:get_value(<<"tests">>, Doc, null), 
    lists:foreach(fun({L}) -> Emit(Name(L), Status(L)) end, Tests) 
end. 
Cuestiones relacionadas