Funciones Cloud de FireBase

sábado, noviembre 2nd, 2019

Hace tiempo desarrollé dos aplicaciones en angular, usando como backend la base de datos firebase; como estaba aprendiendo la plataforma y familiarizandome con los nuevos conceptos, fue difícil entender algunos conceptos nuevos.

Uno de los hechos que mas me desconcertó fue el hecho que en la bases de datos NOSQL no se pueden hacer consultas sum() avg() max() min().

Para poder solventar esta situación, muchos blogs sugieren usar funciones cloud, estas trabajan del lado del servidor, obteniendo y manipulando la data, a continuación te comparto lo que encontré en mi búsqueda por resolver este problema.

Cloud Functions de Firebase

Primero que nada debemos instalar la herramientas de firebase Tools en nuestro proyecto local.

npm install -g firebase-tools

Luego hay que crear un directorio antes que pueda almacenar nuestro proyecto, como uso Linux, este procedimiento de crear un proyecto se crea muy fácilmente

cd ~/Documents/DESARROLLO/angular
mkdir fb
cd fb/

Una vez creado instaladas la firebase tools y creado un directorio de trabajo podemos iniciar sesion en firebase, para esto debemos escribir en la consola el siguiente comando

firebase login

con esto nos deplegará un login de google donde podemos seleccionar la cuenta en la cual tenemos almacenados nuestros proyectos de firebase

Seleccionamos la cuenta y podemos logearnos para crear un proyecto ó bien seleccionar un proyecto de los que tenemos en la consola

firebase init functions

Con el comando anterior ya podemos crear un directorio para trabajar con las funciones de firebase, nos quedará una estructura de archivo como la siguiente.

Fuente de este tutorial: https://carlosazaustre.es/que-son-las-firebase-cloud-functions/

Escribiendo una función en firebase

En el paso anterior vimos como hacer para poder configurar un proyecto de funciones firebase, ahora veremos como escribir la primera función firebase, para este tutorial usamos como fuente el video de codigofacilito que puedes visitar aquí

Me gustó mucho este tutorial por que esta escrito con TypeScript, y en angular se trabaja con TypeScript, por eso se me hizo más fácil seguirlo, muy buen trabajo de nuestros amigos de CodigoFacilito.com

Paso 1) iniciar el proyecto

Debemos iniciar el proyecto estando en el directorio que creamos anteriormente, y ejecutar el comando siguiente

firebase init 

Esto nos despliega una pantalla con el siguiente menú

Debes seleccionar Functions con la barra espaciadora y presionar enter, a continuación te pedirá si deseas crear un proyecto nuevo o como en mi caso seleccionar uno que ya existe

luego te preguntará el lenguaje que usaras para escribir las funciones

te pedirá que instales las dependencias entre otras cosas, yo le di que si a todo, haz lo mismo

Cuando termine de instalarse las dependencias tendrás listo el directorio para poder escribir tus funciones.

Abriremos el archivo index.ts que se encuentra en la carpeta src de nuestro proyecto

Y ahora si podemos escribir nuestra función perfectamente, para el ejemplo escribiremos una función que nos devuelva un hola mundo desde una dirección en internet, algo que debes entender de firebase Cloud Functions es que son el equivalente a los archivo php de nuestro servidor apache, escribe lo siguiente en el archivo

index.ts 
import * as funciones from 'firebase-functions';
exports.add=funciones.https.onRequest((req,res)=>{
    res.send('<p>'+'Hola Mundo'+'</p>');
});

Una vez hecha la función hay que deployarla en el servidor

firebase deploy --only functions

Atención: a partir de enero 2020 lo planes de facturación para Cloud Functions de Firebase cambian, es importante que atiendas este documento en el que te explico la nueva forma de cobrar de firebase

para ver el resultado debes ejecutar en el navegador la dirección de tu función en el servidor de firebase, por supuesto que esto varía según la cuenta del usuario y proyecto seleccionado

https://us-central1-TUPROYECTO.cloudfunctions.net/add

DEBES SUSTITUIR TUPROYECTO POR EL NOMBRE DE TU PROYECTO

Y verás el resultado de tu función en el navegador

Cloud Function para escribir en una base de datos

También es posible utilizar Cloud Function para escribir en una base de datos de Firebase, para esto necesitamos instalar la librería el SDK de firebase-admin

npm install firebase-admin --save

una vez instalado debemos importarla al proyecto en el archivo index.ts

import * as admin from 'firebase-admin';

a continuación hay que inicializar la app con el comando initializeApp

admin.initializeApp(funciones.config().firebase);

Luego ya podemos empezar agregando un valor a una colección de Cloud Firestore

admin.firestore().collection('nuevo').add({
        text:req.query.text
    }).then(r=>{
        res.send('completado');
    }).catch(err=>{
        res.send('hubo un error');
    })

Ahora debemos consumir a function enviando un parámetro para que pueda ser recibido por la function e introducido en una colección

https://us-central1-TUPROYECTO.cloudfunctions.net/add?text=nuevo

La función tomará el parámetro y lo introducirá en la colección

Triggers en Cloud Firestore

Todo lo anterior esta muy bien, pero todavía no definimos como definiremos las funciones de agregado: sum(), avg(), max(), min().

Lo primero es que si venimos del mundo SQL, es obligación cambiar nuestra manera de organizar los datos.

Por ejemplo en bases de datos NOSQL como FireStore, no puedes obtener el conteo de una colección, sin consumir gran cantidad de transacciones del servidor.

Puesto que el cobro por transacción, es la forma de facturar que aplica Firebase, es indispensable que tengamos en cuenta lo siguiente:

Si tuvieras una colección con los pagos que ha realizado un usuario, y quisieras saber el monto total de los pagos, siendo que este usuario ha realizado 1k transacciones este año.

Para saber ese dato tendrías que realizar 1k transacciones para leer la base de datos y sumar a uno por uno los pagos, como el cobro se hace por transacción y hay un límite al momento de escribir este artículo de 50k diarias en la versión gratis, con solo 50 usuarios que consulten su historial de pagos, tu plan gratuito pasaría al siguiente nivel y se te cobraría.

Es por eso que cuando usas Firebase, lo correcto es usar una cloud Function que se encargue de escribir los valores de agregado en un documento aparte.

A continuación te muestro como resolví este problema, usando el siguiente video de codigofacilito.com, en el cual se explica perfectamente este punto

Primero que nada creamos una colección en la base de datos para contener el numero de registros, debes ir a tu consola web y crear lo siguiente

Luego debemos ir al archivo index.ts y agregar una nueva función lo cual hacemos así

exports.contador=funciones.firestore.document('nuevo/{itemid}').onCreate((ev)=>{
    
});

Importante destacar que el {itemid} es un wildcard que sirve para ser sustituido con el id del documento que se está agregando

A continuación debemos crear una referencia que apunte al contador


exports.contador=funciones.firestore.document('nuevo/{itemid}').onCreate((ev)=>{

    const doc =admin.firestore().doc('counter/items');
    
});

hecho esto ya podemos usar el método get() para obtener el documento counter obtener el valor, sumarle uno y luego actualizarlo en la bd

 return doc.get().then(
        (result)=>{
            const info = { value: result.data()!.value +  1 };
            return doc.update(info);
    })  

Esta porción de código obtiene el valor le suma uno y lo escribe en el contador, importante ver el símbolo de admiración que hay en result.data()! esto es así para decirle que ignore la posibilidad que el valor devuelva un null, con esto asumimos que el documento counter siempre existirá.

El código completo del archivo index.ts queda así

import * as funciones from 'firebase-functions';
import * as admin from 'firebase-admin';

admin.initializeApp(funciones.config().firebase);
//las functions 
exports.add=funciones.https.onRequest((req,res)=>{
    //res.send('<p>'+'Hola Mundo'+'</p>');
    admin.firestore().collection('nuevo').add({
        text:req.query.text
    }).then(r=>{
        res.send('completado');
    }).catch(err=>{
        res.send('hubo un error');
    })
});

exports.contador=funciones.firestore.document('nuevo/{itemid}').onCreate((ev)=>{
    const doc =admin.firestore().doc('counter/items');
 
      return doc.get().then(
        (result)=>{
            const info = { value: result.data()!.value +  1 };
            return doc.update(info);
    })  
})

y el resultado final es el siguiente en la bd

Compartir esto en:
Twitter |Facebook |Whatsapp |Google+ |Linekdin |Pinterest


Deja una respuesta