Después de la introducción a CouchDB que vimos en el primer post ahora toca ponerse manos a la obra y empezar a trabajar. Veremos algunos ejemplos prácticos de como trabajar con CouchDB, tanto desde el interfaz web que nos ofrece como directamente.
Instalación
Lo primero es instalar CouchDB en nuestro ordenador. Si tenemos Ubuntu en su última version (Karmic=9.10) podemos instalarla directamente desde los repos oficiales:
apt-get install couchdb
Hecho esto podemos arrancar el servidor de CouchDB como con cualquier otro demonio mediante el /etc/init.d/couchdb. A este se le puede pasar como parametros start, stop, restart... según la acción que queremos realizar.
Una vez arrancado el servidor podemos comprobar que funciona abriendo esta dirección en el navegador: http://localhost:5984/_utils
Aquà veremos la aplicación de administración de CouchDB (llamada Futon):
Antes de nada vamos a comprobar que todo funciona correctamente en nuestra instalación. Para ello pulsamos donde pone “Test suite”. Veremos una pantalla con todos los tests que trae de serie CouchDB y si queremos podemos darle a “Run all” para que se ejecuten todos. A no ser que haya algún problema raro todos los tests darán el resultado success.
Primeros pasos
Nada mas entrar vemos que no tenemos ninguna base de datos nuestra, si queremos podemos crear una desde el interfaz pulsando en “Create database“. Vamos a llamarle blog, por ejemplo. Tras darle a “Create” ya estamos dentro de nuestra base de datos preparados para empezar a introducir documentos en ella. Si queréis volver al listado de bases de datos podéis pulsar en “Overview” (arriba del todo a la izquierda).
Para añadir un documento nuevo le damos a “New document” y empezamos a introducir los atributos que queramos y los valores de estos. Recordad que para el contenido de nuestros atributos sólo podemos usar valores validos en JSON. Por ejemplo, crearemos un documento que tenga esta pinta:
Si os fijáis el campo tags tiene 2 valores. Para hacer esto hay que poner como valor un array de strings:["personal", "chanante"]
Le damos a “Save Document” y ya está. Sencillo, ¿verdad?.
También podemos ver el documento más en “crudo” si pulsamos en la pestaña que pone “Source“, desde esta vista también podemos editarlo (con doble click), siendo mucho más fácil copiar y pegar un documento entero.
Si volvemos a la base de datos blog veremos como aparece nuestro primer documento en la lista. ¿Y cómo se puede recuperar este documento desde fuera? Pues con esta url: http://localhost:5984/blog/7b7e4df4fd5744c990ac624bc0fe15c3 (o bien si no queremos escribirla a mano podemos pulsar el botoncito oscuro que hay justo encima de la pestaña “Source“)
De cualquiera de las 2 formas veremos nuestro documento en formato JSON. Esta es la url desde la que podremos recuperar el documento desde fuera, por ejemplo desde nuestro programa.
Trabajando con las views
Como comentamos de pasada en el primer artÃculo las views se almacenan en unos documentos especiales de nuestra BD llamados design documents. Pero también podemos crear vistas temporales que se ejecuten directamente sin guardarse en la BD. El problema con estas últimas es que el rendimiento no es muy bueno, ya que no se crea el Ãndice que permite que las ejecuciones posteriores sean muy rápidas.
Primero empezaremos creando una vista temporal sobre la que haremos prueba, pero antes de ello necesitamos algunos documentos más. Crearemos un par de documentos con el siguiente contenido (Podéis usar la pestaña “source” para pegar estos documentos).
{
"_id": "d205cff5d6ca0a061f7c0b791f7d5848",
"_rev": "1-b07459bf5a73132b6b83d8732d720883",
"titulo": "Peli del sabado",
"contenido": "Voy a contaros la última peli que he visto",
"posteado": "2009/12/01 14:10",
"tags": [
"personal",
"cine"
]
}
{
"_id": "6de9e5880be29ecd6cba07fa514f7204",
"_rev": "1-fa442e4c48128b3cd8b88cf597b8ba1b",
"titulo": "Programación orientada a demos",
"contenido": "Un nuevo paradigma de programación",
"posteado": "2009/12/02 15:00",
"tags": [
"informatica"
]
}
Ahora vamos a crear una view sencilla, seleccionado “Temporary view…” en el desplegable de la derecha. En el textarea de la función Map vamos a poner esto:
function(doc) {
emit(doc.posteado, doc);
}
Y le damos a “Run”, con lo que tendremos algo parecido a esto:
Como veréis solo salen 2 documentos ya que al primero no le hemos puesto el atributo posteado. Aquà hacemos un inciso, aunque CouchDB sea una base de datos de sin esquema podemos definir una función de validación que se ejecuta cuando intentamos introducir un documento realizando las comprobaciones que consideremos necesarias.
No hay que olvidar que desde la función de Map podemos emitir todos los resultados que queramos, adaptemos la view que enseñamos en el primer post de CouchDB.
function(doc) {
for (var i in doc.tags)
emit(doc.tags[i], doc);
}
Volvamos al lÃo. Ahora abrimos una nueva pestaña (para no perder la view que estamos editando; acordaos también de seleccionar “All documents” en el desplegable de la derecha para ir a la lista de documentos) y ponemos un campo posteado al documento inicial. Por ejemplo ponemos “2009/11/30 10:05″.
Si volvemos a la pestaña donde tenemos la view y le damos a “Run” veremos como aparecen los 3 documentos.
Ahora supongamos que queremos guardar esta view para poder utilizarla como una consulta (y de paso aprovecharnos del indice que se crea al guardarla). Le damos al “Save as” y nos pide que introduzcamos el nombre del design document y de la propia view. Si os fijais el design document empieza por _design, este es un patrón común en las urls de acceso a CouchDB para identificar cosas “especiales”. En este caso nos indica que detrás va el nombre de un design document. P.ej. lo llamamos “cons” y a la view “por_fecha“.
Al guardar veremos una página similar a la de la view temporal pero ahora está plegada la parte del código (donde pone “View Code“). Si clickamos en el botón que hay encima del desplegable de la derecha veremos como se accederÃa al resultado de esta view desde fuera.
Si queremos obtener el post que hicimos en una fecha determinada podemos usar el parámetro key:
http://localhost:5984/blog/_design/consultas/_view/por_fecha?key="2009/11/30 010:05"
Y si queremos obtener los que hay entre un rango de fecha podemos usar los parametros startkey y endkey:
http://localhost:5984/blog/_design/consultas/_view/por_fecha?startkey="2009/11/30 10:05"&endkey="2009/12/01 21:00"
Esto funciona porque hemos puesto la fecha en un formato ordenable lexicográficamente. Esto es porque CouchDB no tiene un tipo date especial, para él es un simple string. Recordad que para CouchDB solo se permiten los tipos válidos de JSON. Bueno, también tenemos la opción de poner attachments en nuestros documentos si queremos subir ficheros binarios como imágenes o demás.
Si queremos que se ordenen los resultado al revés podemos pasarle el parámetro descending=true. Si hacemos esto hay que ir con cuidado con startkey y endkey , habrá que invertir sus valores para obtener el resultado esperado. Esto es asà porque CouchDB, después de aplicar el orden que le decimos, empieza a devolver documentos empezando desde el primero (o desde startkey si se lo pasamos) y acaba en el último (o en endkey si se lo pasamos).
En las vistas podemos usar funciones de javascript sin problemas, pudiendo incluso hacer cosas como new Date(doc.posteado) sin problemas. Por ejemplo, si sustituimos el código de nuestra view por este:
function(doc) {
var v = doc.posteado.split('/');
emit( [v[0], v[1]], 1 );
}
Y le damos a”Run” veremos que nos devuelve filas con el año y el mes como clave y un 1 como valor.
Otro hecho interesante es que existen servidores de views que funcionan con otros lenguajes como Python o Ruby (y asà podemos acceder a la gran cantidad de librerÃas soportadas en estos). Asi que si Javascript se nos queda corto siempre tenemos la opción de definir nuestras views en un lenguaje diferente.
Podéis pensar que el ejecutar una función de Javascript (o Python o Ruby…) para cada documento será muy lento, pero esto no es asà ya que una vez creado el Ãndice no se vuelve a ejecutar esta función. Bueno, si que se ejecuta, pero solo puntualmente para aquellos documentos que se modifiquen a posteriori.
Volviendo al nuestra función Map vemos que ahora devolvemos un 1 en vez de doc. Esto se hace para poder contar los posts que tenemos en cada mes. Y aquà es donde entra la parte reduce.
Ponemos esto en el textarea del Reduce:
function(keys,values,rereduce)
{
return sum(values);
}
Si le damos a “Run” vemos como ya tenemos la cuenta de todos los documentos que hay para cada mes. La función sum está ofrecida por CouchDB y realiza la suma de los values por nosotros.
En cuanto a como es llamada la función reduce hay un detalle interesante. Esta puede ser llamada por CouchDB tanto con claves y valores emitidos por la función Map tanto como claves y valores intermedios obtenidos de una ejecución de la propia función reduce. Esto es asà por como se organiza el Ãndice que se crea cuando guardamos la view. El Ãndice se va generando “a lotes” con lo que CouchDB va invocando la función reduce pasándole conjuntos de keys y values cada vez. No le entran todos de una sola vez. Además de esto, esta función puede ser llamada pasándole el resultado intermedio obtenido de procesar uno de estos grupos de keys y values.
Un ejemplo rápido para acabar de entender la idea. Pensemos en 10 pares de keys y values. Primero CouchDB hace 3 llamadas llama a la función reduce pasándole los elementos (1,2,3,4), (5,6) y (7,8,9,10). Después hace 1 llamada pasándole los resultados de cada uno de los grupos (resul1, resul2, resul3).
Aquà entra el juego el parámetro rereduce que recibe la función.
Si rereduce==false quiere decir que le estan entrando keys y values directamente de la ejecución del Map. Esto no quiere decir que le entren todos de una vez, sino que le le pueden ir entrando “a cachos” (2 resultados, luego 10, luego 5… etc). En este caso los parámetros keys y values contienen esto:
- keys: Array de arrays [key, id] donde key es la clave que emitimos desde la función Map y id es el del documento que emite esa key.
- values: Array de los valores emitidos por las claves correspondientes
- Ejemplo de parámetros que le entrarÃa a la función Reduce: reduce([ [clave1,id1], [clave2,id2], [clave3,id3] ], [valor1,valor2,valor3], false)
Si rereduce==true quiere decir que le están entrando valores de una ejecución previa de la propia función Reduce. Por lo tanto recibirá los siguientes valores en sus parámetros.
- keys: recibe null
- values: Array de valores previos devueltos por llamadas a la función reduce
- Ejemplo de parámetros que le entrarÃan a la función Reduce: reduce(null, [intermedio1,intermedio2,intermedio3], true)
Volviendo a nuestro ejemplo, si le damos al botón de arriba del combo de la derecha podemos ver el resultado de la ejecución de nuestra view (antes nos tocará guardarla).
Obtendremos un resultado asÃ:
{"rows":[
{"key":null,"value":3}
]}
El problema es que nos está reduciendo nuestro resultado hasta obtener 1 solo número. Como nosotros queremos que nos devuelve la reducción para cada una de las claves diferentes le tenemos que pasar el parámetro group=true.
Trabajando a mano
Para acabar vamos a ver unos ejemplos rápidos de como consultar contra nuestra BD desde fuera. Los veremos usando el programa curl que nos permite realizar peticiones web desde la lÃnea de comandos. Pasamos desde la comodidad del interfaz web que nos ofrece Futon a un modo lo mas parecido posible a como recuperarÃamos datos desde nuestros programas.
Si le pasamos -X al comando curl podemos especificar el método de HTTP que se utilizará para realizar la petición.
Recuperar versión de nuestra instalación de CouchDB:
curl http://localhost:5984
{"couchdb":"Welcome","version":"0.10.0"}
Ver las BDs que tenemos:
curl http://localhost:5984/_all_dbs ["test_suite_db_a","test_suite_users","test_suite_db_b","test_suite_db/with_slashes","test_suite_db","blog"]
Crear una BD nueva:
curl -X PUT http://localhost:5984/prueba
{"ok":true}
El hecho de pasarle PUT aquà es por respetar la semántica habitual de los servicios REST, si GET sirve para leer PUT se usa para indicar que hay que crear ese objeto (en este caso la BD).
Borrar la BD:
curl -X DELETE http://localhost:5984/prueba
{"ok":true}
Crear un nuevo documento (Ojo que tenéis que crear otra vez la BD prueba si habéis ejecutado la orden del DELETE):
curl -X PUT http://localhost:5984/prueba/8765rftded6c29495e54cc05947f18c8af -d '{"titulo":"Hola","contenido":"Tarari"}'
{"ok":true,"id":"8765rftded6c29495e54cc05947f18c8af","rev":"1-2595bee478858db4cd88b5500adfb4a5"}
Esta orden nos devuelve el la revisión del documento creado. Esta revisión es util cuando queremos modificar un documento. Por ejemplo, que pasa si ejecutamos otra vez el mismo comando:
curl -X PUT http://localhost:5984/prueba/8765rftded6c29495e54cc05947f18c8af -d '{"titulo":"Hola","contenido":"Tarari"}'
{"error":"conflict","reason":"Document update conflict."}
Nos da un error porque no sabe que versión de documento queremos modificar (no le hemos indicado ninguna) . Si queremos actualizar ese documento tenemos que pasarle el _rev del documento en cuestión (cuidado que la primera orden esta en 2 lÃneas para que quede bien en el blog):
curl -X PUT http://localhost:5984/prueba/8765rftded6c29495e54cc05947f18c8af -d \
'{"titulo":"Hola","contenido":"Tarari", "_rev":"1-2595bee478858db4cd88b5500adfb4a5"}'
{"ok":true,"id":"8765rftded6c29495e54cc05947f18c8af","rev":"2-6f2c18312298f1c3327b39f52cea5ba1"}
Como vemos nos devuelve el numero de versión cambiado (incrementado lo de antes del – y lo de después del – modificado). Si volvemos a ejecutar el mismo comando fallará ya que la última versión existente es la 2-6f2c18312298f1c3327b39f52cea5ba1.
También podemos llamar con curl a las views que habÃamos definido anteriormente:
curl "http://localhost:5984/blog/_design/consultas/_view/por_fecha?startkey=%222009/11/30%2010:05%22&endkey=%222009/12/01%2021:00%22"
{"total_rows":3,"offset":0,"rows":[
{"id":"7b7e4df4fd5744c990ac624bc0fe15c3","key":"2009/11/30 10:05","value":
{"_id":"7b7e4df4fd5744c990ac624bc0fe15c3",
"_rev":"4-beee38d3b358e5c533f907f77340e7bb","titulo":"Mi primer post",
"contenido":"Atiende muchacho, este es el primer post de mi blog","tags":["personal","chanante"],"posteado":"2009/11/30 10:05"}},
{"id":"d205cff5d6ca0a061f7c0b791f7d5848","key":"2009/12/01 14:10","value":
{"_id":"d205cff5d6ca0a061f7c0b791f7d5848",
"_rev":"3-eb0359248144f982d89648dcb60d450a","titulo":"Peli del sabado",
"contenido":"Voy a contaros la ultima peli que he visto","posteado":"2009/12/01 14:10","tags":["personal","cine"]}}
]}
En la lÃnea del curl hemos codificado para url los ” y los espacios en blanco para que no nos molestaran en la linea de comandos. Esto es cosa del shell de linux y como trata estos carácteres, desde nuestro programa seguramente no harÃa falta escaparlos.
Si queréis ver más sobre views complejas podéis probar en este emulador de querys de CouchDB o si queréis en el wiki oficial.





964 387 506
Me encanta
.
Estoy empezando a profundizar con Erlang y me interesa mucho esta serie de artÃculos.
Cojonudo, Gracias por todo
Buenas, me han parecido muy buenos tus dos artÃculos sobre CouchDB, harás alguno más? Me parece un tema muy interesante y del que apenas hay información en español.
Otra cosa que me gustarÃa preguntarte es cómo saber que tipo de base de datos usar dependiendo de la aplicación, es decir, hay bases de datos basadas en grafos que se supone que son las ideales para las cosas de redes sociales y tal, otras que son bases de datos documentales como CouchDB, y las bases de datos relacionales. Me encantarÃa si pudieras explicar cuando usar unas u otras, porque tengo un cacao mental increÃble, y todos los artÃculos decentes sobre este tema están en inglés, y no me aclaro muy bien
Un saludo y muchas gracias por compartir tu conocimiento crack!
Perdona, también se me olvidó comentarte que a ver si podÃas decir las ventajas en cuanto a rendimiento de unos tipos de bases de datos frente a otras. Porque yo supongo que la simpleza y el ‘schema less’ del CouchDB este, en algún sitio tiene que notarse no? Supongo que una RDBMS bien optimizada y bien indexada se mea al CouchDB, o no?
Si, estamos preparando uno sobre otras bases de datos NoSQL, estad atentos al blog
Aquà depende de lo que quieras guardar y como lo vas a consultar. Si es una información que tiene una estructura fija y normalizada (o que va a ir cambiado poco a poco y de forma gradual) es recomendable usar una BD relacional de las de toda la vida. Y tambien si nos ponemos a hablar de transacciones, aqui en general estas BD NoSQL suelen ofrecer poco al respecto…
En definitiva, por muy bonitas que sean estas BD NoSQL, son utiles en ciertos casos de uso especificos, pero las BD tradicionales siguen siendo intocables en usos “normales”.
Ya se que el ingles no es lo tuyo, pero echale un ojo a esta presentación y veras como te aclara algunas dudas:
[url]http://slidesha.re/4e6gXH[/url]
Pues depende… CouchDB por ejemplo no es un cañon comparado con MySQL (sobre todo en inserciones), pero resulta que llegado el momento de escalar ofrece unas facilidades (como puede ser el soporte de replicacion nativo) que son ideales.
Y luego no todo es CouchDB, tambien hay otras BD similares como puede ser MongoDB que ofrecer un rendimiento comparable (por no decir mejor) que MySQL.
Hola 4TIC!
Tienes que ayudarnos/explicarnos couchApp.
Es la única menera de hacer apps con couchDB que estén integradas en la propia couchDB, y volver a las aplicaciones de 2 capas.
thanks
Podrian decirme como acceso desme mi aplicacion hecha en asp.net a couch db???
es urgente por favor ayuda