Ionic Framework, PouchDB y Cloudant: la combinación perfecta totalmente expuesta Parte 07


Esta es una continuación de la serie sobre desarrollo en móviles que comencé aquí. Les recomiendo comenzar a escribir el código fuente desde la parte 1 ya que no se publica el código para descarga.

El mayor desafio que hay al trabajar con NOSQL es consultar los datos pues no hay algo como SQL del mundo relacional que venga y nos simplifique la vida, bueno, si hay pero en cuestión de rendimiento no es lo mismo. CouchDB originalmente viene con funciones Map/Reduce para la creación de índices o vistas, es decir, si queremos recuperar los datos en cierto orden o hacer consultas tipo select * from tabla where campo3=XXX debemos crear un índice para poder buscar por el campo3, el problema es que como no hay tablas estos índices se aplican a todos los documentos en la base de datos y un detalle importante: estos índices se graban en disco lo que los hace muy eficientes. Suena bonito. Veamos como se hace.

Digamos que en nuestra aplicación de noticias queremos agregar secciones tal como lo tienen todos los sitios de noticias: política, espectáculos, deportes y así. Bien, entonces agreguemos los documentos a la base en Cloudant. Empecemos con 3 categorías.


{
 "_id": "cat_01",
 "nombre": "Nacional",
 "descripcion": "Noticias del país",
 "tipo": "topic"
}

{
"_id": "cat_02",
"nombre": "Internacional",
"descripcion": "Noticias del mundo",
"tipo": "topic"
}

{
"_id": "cat_03",
"nombre": "Espectáculos",
"descripcion": "Cine, TV y música",
"tipo": "topic"
}

{
"_id": "cat_04",
"nombre": "Opinión",
"descripcion": "Punto de vista de los editores",
"tipo": "topic"
}

Listo, 4 categorías para comenzar. Recuerden ingresar estos 4 documentos en su página de Cloudant. Seleccionen la base de datos y luego busquen la opción agregar doc.

addNewDoc

Ingresen uno a uno las 4 categorías.

Importante es el campo “tipo” que nos indicará que estos 4 documentos pertenecen a un tipo “topic” que es como identificaremos a esta entidad. Ahora tendremos en la base de datos documentos tipo “topic” y tipo “news”. Ahora lo que tenemos que hacer es vincular los documentos, así que iremos revisando los documentos tipo “news” uno por uno asignándole un topic. Por ejemplo:

{
 "_id": "news_20150724_vpease_001",
 "_rev": "2-6713e069e048d0eeb4d8d826f52454cd",
 "tipo": "news",
 "titular": "Retomando el demo!",
 "resumen": "Regresando a la lector de noticias esta vez con estados",
 "fecha": "2015/07/24",
 "autor": "vpease",
 "topic": "cat_01"
}

En la línea 9 podrán ver que se ha agregado el campo “topic” y el valor que tiene es el id de la categoría 1: “Nacional”.

Ahora necesitaremos una forma de recuperar la lista de categorías para mostrarlas en el app y luego al seleccionar cada una, mostremos las noticias asociadas.Las opciones que tenemos son :

  • Crear una vista: En el servidor buscaremos todos los documentos tipo “topic” y los devolveremos. Como todo índice, va a crear un archivo físico.
  • Usar el índice por defecto: podemos consultar el índice por defecto utilizando el Id. Si vemos el id que hemos fijado, todos los documentos tipo “topic” tienen un Id del tipo “cat_XXX” así que podemos usar esto para recuperarlos. Se reutiliza el índice principal.
  • Cloudant Query. Es el nuevo motor de búsqueda que viene con CouchDB 2.0 que es más fácil de usar que Map/Reduce. Igualmente creará un índice en un archivo físico.

Tengan en cuenta que:

  • Si crean un índice, se crea un archivo. Esto es tanto en el servidor como en el lado del cliente.
  • Ya existe un índice por defecto que nos permite consultar por el id.

Además, gracias al buen artículo publicado por Nolan Lawson en http://pouchdb.com/2014/05/01/secondary-indexes-have-landed-in-pouchdb.html, lo más conveniente es explotar al máximo el Id principal del documento.

Cloudant Query lo guardaremos para el siguiente post, así que por ahora vamos a utilizar la siguiente estrategia:

  • Crear una consulta al Id para recuperar la lista de categorías
  • Crear una vista para recuperar todas las noticias dentro de una categoría.

Empecemos creando la vista. Esto debemos hacerlo en Cloudant y luego será sincronizada automáticamente al cliente en PouchDB. Recuerden que para PouchDB esto se llama índices secundarios. En la pantalla de Cloudant vamos a la opción de crear vistas.

createview

Ahora le damos un nombre a nuestro documento de diseño, para hacerlo simple llamaremos ‘news’ a este documento. Un documento de diseño es donde se definen los indices y otras reglas en CouchDB. Le pondremos el nombre topics a la vista. CUIDADO:  el nombre del documento de diseño es la raíz para cuando quieran llamar a su vista. En nuestro caso, el nombre completo de nuestra vista será ‘news/topics’.

Lo importante es que queremos poder buscar las noticias por la categoría a la que pertenecen, para eso escribimos lo siguiente en la sección Map function:

function (doc) {
if (doc.tipo =="news") {
emit([doc.topic], {_id:doc._id});
}
}

Tremenda ensalada para tan pocos comandos. Lo que hace esto es recuperar todos los documentos tipo news y publicar el índice doc.topic que como ya saben es el campo que tiene la categoría de la noticia, luego le decimos que devuelva todo el documento con la información de la noticia.

La función Reduce es opcional y se usa para cuando queremos realizar una operación sobre los datos obtenidos, en otras palabras, para los nativos SQL es cuando usamos funciones tipo Sum, Count y esas cosas. Para este caso, no nos hace falta.

Y listo, ahora el documento de diseño será sincronizado con PouchDB en el cliente y podremos hacer las consultas, pero antes debemos cambiar el diseño de nuestra aplicación, Para no alargar este post, vamos a hacer un cambio simple, mostraremos solamente las noticias que pertenezcan a la categoría ‘cat_01’ que corresponde a las noticias nacionales.

Primero, comencemos agregando al servicio db un método para consultar la vista que acabamos de crear.


var mostrarCat = function(catId){
db.query('news/topics',{startkey:[catId],include_docs:true,descending:true})
.then(function(result){
$rootScope.$broadcast('refrescar',result.rows);
});
}

El nombre de la vista es ‘news/topics’, noten que comenzamos por incluir el documento de diseño, porque simplemente puede haber más de uno, pero no compliquemos el asunto por ahora. luego están las opciones que hemos incluido:

  • startkey: simple, es el valor que queremos comparar. Como nuestra clave fue definida simplemente por el campo doc.topic entonces es una cadena simple. Es posible definir mas campos en el índice y en ese caso tendríamos que pasar un array. En este parámetro pasamos el id de la categoría que queremos ver.
  • include_docs: Por defecto, CouchDB devuelve solamente el Id del documento asociado, pero como necesitamos mostrar la noticia completa, tenemos que fijar este parámetro en true.
  • descending: indica que el resultado será ordenado por la clave original en modo descendente, recuerden que la clave original tiene la fecha en el formato YYYYMMDD de tal forma que si la ordenamos en forma descendente tendremos las noticias nuevas al comienzo.

Y listo, ahora solo falta indicarle al código del servicio que en lugar de utilizar el método “mostrar()” , donde se recuperan todas las noticias, utilice “mostrarCat(“cat_01″)” donde le decimos que nos muestre solamente los de la categoría “cat_01” que corresponde a las noticias nacionales. Algo tosco pero efectivo. El código del servicio ‘db’ quedará así:


angular.module('services',[])
.factory('db',function($rootScope){
var key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
var pass = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
var remote = 'https://'+key+':'+pass+'@server.cloudant.com/news';
var db;
var mostrar = function(){
db.allDocs({startkey:'news_\uffff',endkey:'news_',descending: true,include_docs:true})
.then(function(result){
$rootScope.$broadcast('refrescar',result.rows);
});
};
var mostrarCat = function(catId){
db.query('news/topic',{startkey:[catId],include_docs:true,descending:true})
.then(function(result){
$rootScope.$broadcast('refrescar',result.rows);
});
}
return {
init: function(){
if (!db) {
db = new PouchDB('news');
};
mostrarCat("cat_01");
this.replicate();
},
replicate: function(){
db.replicate.from(remote,{live:true,retry:true})
.on('paused',function(info){
mostrarCat("cat_01");
});
},
get: function(id){
return db.get(id);
}
}
})

Podrán ver aquí que hemos agregado el método mostrarCat en la línea 13 y luego cambiamos la función para mostrar los datos en la línea 24 y en la 30. Fijense que no hemos tenido que mostrar el Controller para nada.

Al ejecutar este nuevo código notarán que ya no tendrán todas las noticias que solían tener, ahora verán una o dos. Prueben insertando nuevos documentos y cambiando la categoría.

Para la próxima trataremos de insertar el concepto de estados abstractos y sobre todo, pasar datos a un estado, y para arreglar la parte gráfica, agregaremos un bonito menú que nos permita elegir las categorias como cualquier sitio de noticias decente.


  1. David Hepoz

    No me funciona :C, a la hora de hacer el db.query(‘LIGA’), la liga no me lleva (news/topic), mi app no recupera las noticias, mira te mando screen de cloudant:

    Segun mi caso, como se ponde la referencia (news/what), ?
    Gracia de Antemano por tu tiempo.

    • Pásame el db.query completo que estás usando.

    • Es evidente que en mi texto no indica claramente cual es el nombre del documento de diseño. Voy a corregir ese error.

      En el caso de este post, el nombre que estoy usando es ‘news’ y como la vista se llama topics entonces en el db.query se tiene que llamar a la vista de esta manera: ‘news/topics’.

      En tu caso, el documento de diseño se llama ‘Topics’ y tu vista se llama ‘topic’. Por lo tanto, en tu db.query deberás poner ‘Topics/topic’.

      Me avisas.

  1. 1 Ionic Framework, PouchDB y Cloudant: la combinación perfecta totalmente expuesta | Víctor Pease

    […] Part 7 […]




Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s



%d bloggers like this: