miércoles, 9 de marzo de 2022

CRUD en Firebase Realtime Database con Python

firebase


CRUD en Firebase Realtime Database con Python.


Firebase Realtime Database es una base de datos noSQL alojada en la nube que nos permite almacenar y sincronizar nuestros datos en la nube de Google en tiempo real. Los datos se almacenan en como un archivo JSON y se sincronizan en tiempo real para cada cliente conectado. Además podemos acceder a esa base de datos no solamente con Python como vamos a ver en esta píldora, sino también a través de aplicaciones Web, IOS o Android. 

Registro en Firebase.

Para poder utilizar este servicio debemos registrarnos en Firebase, que es la aplicación general. Para ello iremos a la página https://firebase.google.com/ y nos registraremos con nuestra cuenta de Google.

Cuando nos pregunten, tenemos que elegir la facturación Spark que nos proporciona diversos servicios gratuitos 0$/mes, lo cual para un usuario particular nos servirá perfectamente. Si más tarde quieres o necesitas ampliar la cantidad de almacenamiento o número de consultas permitido siempre puedes comprar un plan que te permita adaptarlo a tus necesidades.

La página de inicio que se muestra al loguearnos será una parecida a esta:

pagina inicial de firebae

Para crear una base de datos en tiempo real con Firebase tenemos que seleccionar primeramente "Crear un proyecto".  Una vez hecho lo anterior, tenemos que ponerle un nombre al mismo. 

poner nombre al nuevo proyecto


Luego por defecto, Google nos propone aceptar la utilización de las herramientas de Google Analytics. Le damos a continuar.

google analytics selección


A continuación seleccionamos la cuenta que vamos a escoger para Google Analytics. Podemos usar nuestra cuenta por defecto o crear una nueva para utilizar en Firebase. Yo escogeré la cuenta por defecto.

selección de cuenta para Google analytics

Finalmente le damos a crear proyecto y esperamos a que se configure todo.

finalizando de configurar el proyecto



Panel de control de Firebase dentro de una aplicación.


Lo primero que veremos es la consola de administración. Si has salido de Firebase y vuelves a entrar, la puedes encontrar seleccionando el proyecto y la opción se encuentra arriba a la derecha "Ir a la Consola"

Consola de configuración de Firebase

  • Aspecto del Panel de control - Funcionalidades más importantes:
    • Authentication: desde aquí se puede controlar cuáles son los mecanismos que estarán disponibles para la autenticación de usuarios, tanto email y clave como por redes sociales, junto con los datos de configuración.
    • Firestore Database y Realtime Database: Aquí esta básicamente lo que vamos a hacer en esta píldora. Desde aquí crearemos nuestra base de datos en tiempo real (Realtime Database) cuya estructura básicamente la de un archivo JSON.
    • Storage: para acceder al repositorio de archivos generados por los usuarios (como fotos, vídeos y archivos de audio) sin necesidad de utilizar código de servidor.
    • Hosting: es un espacio de alojamiento donde desplegar la app realizada. Una vez activado también se pueden controlar aquí las configuraciones del hosting.


Seleccionamos donde pone Realtime Database y luego en "Crear una base de datos".

Crear Realtime Database


Luego elegimos el servidor más próximo a nosotros.

elección del servidor


En la siguiente pantalla empezamos a configurar la base de datos. Tenemos dos opciones. Vamos a elegir la primera "Comenzar en modo bloqueado" ya que queremos una base privada que solo pueda acceder quien nosotros demos acceso.


base de datos en modo bloqueo


y con esto ya tenemos nuestra base de datos creada con su dirección URL.


base de datos novatillo creada.


En la parte de arriba hay un menú que pone (Datos, reglas, copias de seguridad y usos). Escogemos "reglas" y cambiamos los valores de "read" y "write" que por defecto están en valor "false" a "true"

definimos true para lectura y escritura


Finalmente de damos a "Publicar" e ignoramos el mensaje informativo de seguridad que nos saldrá.

Es importante que tengamos presente la dirección de nuestra base de datos ya que la necesitaremos para realizar la conexión y gestionar los registros.


dirección de la base de datos

Al crear la base de datos elegimos el "modo bloqueado". Por tanto para poder acceder y modificar los datos, tenemos que usar una clave privada de autentificación de nuestro usuario. Para obtenerla, en la consola del proyecto, justo en la parte de arriba a la izquierda en "Descripción General del Proyecto", al hacer click en la tuerca, nos saldrá un menú que pone "Configuración del Proyecto".

obtención de la clave privada

Lo seleccionamos, escogemos el lenguaje Python y finalmente pulsamos en "Generar nueva clave privada" y después de haber leído el mensaje informativo pulsamos en "Generar nueva clave privada".  Se nos descargará un archivo JSON al ordenador que debemos guardar y no compartir con nadie ya que es la llave de acceso a nuestra base de datos.


CREAR UN SCRIPT DE PYTHON Para guardar datos en Firebase.

Para usar el Firebase Admin SDK, necesitaremos un proyecto de Firebase, una cuenta de servicio para comunicarlos con la base de datos y un archivo de configuración con nuestras credenciales. Todo esto ya lo hemos creado antes.

Ahora empezaremos creando una nueva carpeta  de trabajo que contendrá nuestro código y dentro de ella creamos un entorno virtual.

src $ python3 -m venv miEntorno

Luego lo activamos

src $ source miEntorno/bin/activate

El administrador de Python de Firebase SDK permite a los desarrolladores integrar Firebase dentro de sus servicios y aplicaciones. Para instalar el Firebase Admin Python SDK, simplemente ejecutamos el siguiente comando dentro del entorno virtual:

miEntorno $ pip install firebase-admin

copiamos el archivo JSON, que contiene la clave descargada y que habíamos descargado anteriormente, dentro de la carpeta de trabajo. 

Creamos también un archivo de Python, por ejemplo inicio.py y tecleamos el siguiente código que inicializará el SDK y nos conectará con la base de datos:

inicio.py

# Importamos las bibliotecas necesarias.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})
Básicamente lo que hacemos en las primeras líneas es importar las bibliotecas que vamos a necesitar. Gestionan el funcionamiento del administrador de Firebase, las credenciales de acceso a la aplicación que hemos creado y el funcionamiento de la base de datos.

Posteriormente cargamos el certificado que nos va a permitir conectar nuestra aplicación con el servidor de la base de datos (el archivo JSON que descargamos anteriormente. Tenemos que poner la dirección en donde este este archivo en el ordenador) en la variable cred.

Finalmente inicializamos la aplicación con la dirección URL que identifica nuestra base de datos en tiempo real, la podemos encontrar en el menú DATOS y ya nos la proporcionó Firebase al crear el proyecto (Dirección de nuestra base de datos como puedes ver en la imagen de un poco más arriba)

Estructura de la base de datos.


En Firebase Realtime Database, los datos están estructurados como un archivo JSON (en forma de árbol). A diferencia de las bases SQL, no hay tablas, ni registros. Cuando añadimos datos al árbol JSON, darán lugar a un nodo en la estructura JSON ya existente con una llave asociada. 

La mejor forma para guardar datos en este tipo de archivos es evitar que los datos estén muy anidados y mantener la estructura los más plana posible. Puedes encontar más información en "Como estructurar tu base de datos" en la guía de Firebase.

setEscribir o reemplazar datos en una ruta de acceso definida.
updateActualiza algunas de las claves de una ruta de acceso definida sin reemplazar todos los datos.
pushAgregar datos a una lista de datos en la base de datos. Cada vez que envías un nodo nuevo
a una lista, tu base de datos genera una clave única.
transactionUsa transacciones cuando trabajes con datos complejos que podrían dañarse
con las actualizaciones simultáneas


Método SET.


Para entender como se guardan los datos en Firebase vamos a utilizar el ejemplo que aparece en la documentación de Firebase. Imaginemos que estamos creando un blog y queremos guardar los usuarios  que participan en ese blog, así como los comentarios que realicen. La ruta o referencia donde vamos a guardar los datos será "servidor/datos_usuarios/blog". 

La instrucción básica para guardar datos nuevos en la base de datos es la instrucción "set".  Esta guarda los datos, en la referencia de la base de datos que especifiquemos y reemplaza cualquier dato existente en esa ruta de acceso.

El código de conexión con la base de datos y la especificación de la ruta o referencia señalada, donde se guardarán los datos, es el siguiente: 

inicio.py

# Importamos las bibliotecas necesarias.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia donde se guardarán los datos
ref = db.reference('servidor/datos_usuarios/blog')
La ejecución del código anterior no escribe nada en la base de datos, simplemente señala la referencia donde se escribirán los datos. Ahora vamos a guardar un par de usuarios de este blog imaginario. Almacenaremos cada alias que elija el usuario para participar en el blog, junto con su nombre real y fecha de nacimiento.  Utilizaremos el comando "set" porque vamos a guardar el nombre y fecha de nacimiento bajo el alias de cada usuario. Ese alias será como el id del registro. Posteriormente veremos el método "push" que si crea un id automático del registro.

En el código anterior, ya hemos dicho al programa que la referencia donde se guardarán los datos será "servidor/datos_usuarios/blog" . Dentro de está crearemos una referencia hija "usuarios". A continuación usaremos set para guardar los datos de cada usuario como un objeto que contendrá el alias, nombre real y fecha de nacimiento. Se puede pasar un string, un número, un valor booleano, el valor "null", una matriz o cualquier objeto Json. Si pasamos "null" se borrarán los datos de la ubicación especificada. El código quedaría:

inicio.py - Primer Caso

# Importamos las bibliotecas necesarias.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia donde se guardarán los datos
ref = db.reference('servidor/datos_usuarios/blog')

# Guardamos los datos mediante un diccionario en donde las claves serán los alias de
# los bloguers.
ref_usuarios = ref.child('usuarios')
ref_usuarios.set({
    'pepemaravilloso': {
        'fecha_de_nacimiento': '23 de Junio de 1989',
        'nombre_completo': 'Alvaro Turienzo'
    },
    'lechuga': {
        'fecha_de_nacimiento': '9 de Diciembre de 2003',
        'nombre_completo': 'María García'
    }
})
El resultado será el siguiente. Como puedes ver los id o alias de los usuarios se almacenan por orden alfabético.

guardar datos en real firebase


Otra forma de hacer esto mismo, pero de otra forma sería:

inicio.py - Segundo Caso

# Importamos las bibliotecas necesarias.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia donde se guardarán los datos
ref = db.reference('servidor/datos_usuarios/blog')

# Guardamos los datos mediante un diccionario en donde las claves serán los alias de
# los bloguers.
ref_usuarios = ref.child('usuarios')

# Usuario uno
ref_usuarios.child('pepemaravilloso').set({
        'fecha_de_nacimiento': '23 de Junio de 1989',
        'nombre_completo': 'Alvaro Turienzo'
    })

# Usuario dos
ref_usuarios.child('lechuga').set({
        'fecha_de_nacimiento': '9 de Diciembre de 2003',
        'nombre_completo': 'María García'
    })

En los dos ejemplos anteriores, escribir los datos a la vez que el objeto o escribirlos por separado en ubicaciones secundarias, da el mismo resultado por que partimos de una rama vacía.

Sin embargo existe un matiz IMPORTANTE.  En el primer caso si ya existen registros bajo la clave "usuarios" estos se BORRARAN y serán reemplazados por los que hemos puesto. Sin embargo con el segundo método se añadirán los datos de los usuarios especificados sin borrar los valores previos.


Método PUSH.


A diferencia del método anterior este lo que hace es crear un id o clave única para cada elemento secundario nuevo. Esto nos va a evitar el problema anterior al usar set, que era que al escribir una nueva clave secundaria pudiéramos borrar las ya existentes que estuvieran en la misma ubicación. Esta clave única que genera "push" se basa en una marca de tiempo por lo que todos los elementos de las listas se ordenarán de forma automática. 

Veámoslo el mismo ejemplo de antes. Partimos de la base de datos vacía y vamos a añadir los mismos dos usuarios.

inicio.py 

# Importamos las bibliotecas necesarias.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia o rama donde se guardarán los datos
ref = db.reference('servidor/datos_usuarios/blog')

# Guardamos los datos mediante un diccionario en donde las claves se generarán automáticamente.
ref_usuarios = ref.child('usuarios')

ref_usuarios.push({
    'pepemaravilloso': {
        'fecha_de_nacimiento': '23 de Junio de 1989',
        'nombre_completo': 'Alvaro Turienzo'
    }})
ref_usuarios.push({
    'lechuga': {
        'fecha_de_nacimiento': '9 de Diciembre de 2003',
        'nombre_completo': 'María García'
    }})

El resultado será el siguiente:

usando el metodo push para guardar datos.


Al utilizar push(), se genera una referencia a la ruta de acceso de datos nueva, que podemos usar para obtener la clave o configurar los datos. Por ejemplo si queremos obtener el id o clave generada de un nuevo registro podemos usar el siguiente código. Creemos un nuevo registro y obtengamos su id única.


inicio.py 

# Importamos las bibliotecas necesarias.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia o rama donde se guardarán los datos
ref = db.reference('servidor/datos_usuarios/blog')

# Guardamos los datos mediante un diccionario en donde las claves se generarán automáticamente.
ref_usuarios = ref.child('usuarios')

nuevo_user = ref_usuarios.push({
    'lupita': {
        'fecha_de_nacimiento': '01 de Junio de 1909',
        'nombre_completo': 'Ana Perez'
    }})

print(nuevo_user.key)

Además de escribir este nuevo usuario en la base de datos, obtendremos por pantalla el id generado para el mismo:

id generado para el nuevo registro

modificación de la base de datos


Puedes encontrar más información sobre como guardar los datos en el siguiente enlace.


Como actualizar datos Guardados.


Si queremos actualizar algún usuario, pero sin alterar los datos de los demás, podemos utilizar el comando "update" de la siguiente forma. 

Partiendo del ejemplo anterior vamos a cambiar el nombre completo de pepemaravilloso a "Romanones Perez". Utilizaremos el comando update pero para ello primeramente tenemos que hacer referencia a la rama que queremos modificar. Como si fuera la rama de un árbol, tenemos que seguir la ruta hasta la posición a modificar. Como el dato que queremos actualizar es el de un usuario, la ruta o referencia a esa posición será:

ref = db.reference('servidor/datos_usuarios/blog/usuarios')

Una vez en esta posición el hijo de esa rama a modificar es ('-MxJzEQdI3BrPQnZ2qHI/pepemaravilloso') y a su vez el dato para actualizar esta bajo la clave "nombre_completo".

El código de la actualización sería:

inicio.py 

# Importamos las bibliotecas necesarias.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia donde se actualizarán los datos
ref = db.reference('servidor/datos_usuarios/blog/usuarios')

# Rama hija a modificar.
ref_usuarios = ref.child('-MxJzEQdI3BrPQnZ2qHI/pepemaravilloso')

# Clave a modificar.
ref_usuarios.update({"nombre_completo": "Romanones Perez"})


y de esta forma modificamos esa clave:

update - clave en la base de datos


Otra manera de actualizar los datos es no usar el método child() e indicar directamente en update() un diccionario cuya clave es la ruta completa de la rama a modificar y como valor el dato a modificar. 

En nuestro ejemplo ahora vamos a modificar el nombre_ completo del usuario "lechuga" de "Maria Garcia" a "Pepita Luniega".

inicio.py 

# Importamos las bibliotecas necesarias.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia donde se actualizarán los datos
ref = db.reference('servidor/datos_usuarios/blog/usuarios')

# Rama hija a modificar.
ref.update({'-MxJzES8PBOnqKpcph9p/lechuga/nombre_completo':'Pepita Luniega'})

Ejecutamos el archivo y vemos la diferencia.

otro uso del método update



Recuperar datos de la base de datos.


Vamos a partir de los datos del ejemplo anterior para ver como leer los datos desde una base de datos de real firebase. Vamos a recuperar los datos de los usuarios que hasta ahora tenemos en nuestra base.

Podemos hacer lo siguiente:

inicio.py 

# Importamos las bibliotecas necesarias.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia o rama donde se guardarán los datos
ref = db.reference('servidor/datos_usuarios/blog/usuarios')

# Imprimimos los registros asociados a la rama usuarios.
print(ref.get())

Si ejecutas el código anterior, verás un objeto JSON que contiene todas las entradas.

Salida:

(miEntorno) chema@ubuntu:~/Cursos/Python/firebase$ python inicio.py
{'-MxJzEQdI3BrPQnZ2qHI': {'pepemaravilloso': {'fecha_de_nacimiento': '23 de Junio de 1989',
 'nombre_completo': 'Romanones Perez'}}, '-MxJzES8PBOnqKpcph9p': {'lechuga': {'fecha_de_nacimiento'
: '9 de Diciembre de 2003', 'nombre_completo': 'Pepita Luniega'}}}
También podemos realizar consultas que permiten recuperar datos según varios factores. Para crear una búsqueda en este tipo de base de datos primero hay que especificar como se quieren ordenar los datos mediante alguna de las siguientes funciones:

order_by_child()order_by_key() u order_by_value()

Luego para obtener consultas más elaboradas podemos combinarlas con otros cinco métodos:

limit_to_first()limit_to_last()start_at()end_at() y equal_To().

Para ver esto mejor vamos a crear una nueva base de datos. El código es el siguiente:

inicio.py 

# Importamos las bibliotecas necesarias.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia o rama donde se guardarán los datos
ref = db.reference('Productos')

# Guardamos los diferentes productos.
dato1 = ref.child("echo dot").set({'precio': 34.99, 'cantidad': 2})
dato2 = ref.child("fire tv stick").set({'precio': 24.99, 'cantidad': 5})
dato3 = ref.child("blink outdoor").set({'precio': 64.99, 'cantidad': 12})


Tendrá la siguiente forma:

nueva base de datos de productos.



Para ordenar todos los nodos (en este caso los diferentes productos) por una clave secundaria común (cantidad o precio) podemos pasar esa clave a la instrucción order_by_child(). Por ejemplo, para ver todos los productos ordenados por precio, podemos hacer lo siguiente:


import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia o rama donde se guardarán los datos
ref = db.reference('Productos')

# consultamos los productos ordenamos por precio de menor a mayor.
consulta = ref.order_by_child('precio').get()
for key, val in consulta.items():
    print(f"El producto {key} tiene el siguiente precio {val['precio']}")

Pero si ejecutamos el archivo, así directamente, nos vamos a encontrar con este bonito error.

error al ejecutar archivo


Lo que nos está diciendo el programa es que no tenemos establecido un índice a las reglas de la base de datos para la ruta "/Productos". Pues vamos a establecerlo. Para ello en la consola de firebase vamos al menú de reglas y añadimos el índice de la siguiente forma (vamos a añadir tanto precio como cantidad para poder hacer consultas de ambos campos)

modificación de las reglas para añadir un indice


Puedes encontrar más información sobre reglas para .indexOn en el siguiente enlace.

Cuando ya hemos arreglado esto, si ejecutamos de nuevo el programa obtendremos un resultado bien distinto. El programa nos devolverá un diccionario ordenado de menor a mayor en base al campo precio.

(miEntorno) chema@ubuntu:~/Cursos/Python/firebase$ python inicio.py
El producto fire tv stick tiene el siguiente precio 24.99
El producto echo dot tiene el siguiente precio 34.99
El producto blink outdoor tiene el siguiente precio 64.99
Aunque en este ejemplo no es el caso, cualquier valor que no tenga la clave secundaria que estamos buscando (precio) se ordena con el valor "null" es decir aparecerá primero en el orden. 

Las consultas también se pueden ordenar por campos secundarios profundamente anidados, en lugar de únicamente por campos secundarios de un nivel inferior. Esto resulta útil si tienes campos anidados como estos:

base de datos anidada


Para consultar ahora la base de datos de los productos ordenados por el precio, podemos usar la ruta completa en lugar de una única clave. Para que funcione primeramente tenemos que agregar la regla en la consola de la base de datos:


nueva regla de indexación

Luego el código de la aplicación sería:


# Importamos las bibliotecas necesarias.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia o rama donde se guardarán los datos
ref = db.reference('Productos')

# Consulta a la base de datos anidada.
consulta = ref.order_by_child('caracteristica/precio').get()
for key, val in consulta.items():
    print(f"El producto {key} tiene el siguiente precio {val['caracteristica']['precio']}")
Salida:

(miEntorno) chema@ubuntu:~/Cursos/Python/firebase$ python inicio.py
El producto fire tv stick tiene el siguiente precio 24.99
El producto echo dot tiene el siguiente precio 34.99
El producto blink outdoor tiene el siguiente precio 64.99


También podemos ordenar los diferentes nodos ( distintos productos) por sus claves con el método order_by_key(). En el siguiente ejemplo se leen todos los productos por orden alfabético:

# Importamos las bibliotecas necesarias.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia o rama donde se guardarán los datos
ref = db.reference('Productos')

# realizamos la consulta a la base de datos
consulta = ref.order_by_key().get()
for elemento in consulta:
    print(elemento)

Salida:

(miEntorno) chema@ubuntu:~/Cursos/Python/firebase$ python inicio.py
blink outdoor
echo dot
fire tv stick

Ordenamiento por Valor.


Puedes ordenar los nodos por el valor de sus claves secundarias a través del método order_by_value(). Si suponemos que tenemos esta base de datos en la que solo llevamos un registro de los precios de los productos con el siguiente formato:

{
  "Productos": {
    "blink outdoor" : 64.99,
    "echo dot" : 34.99,
    "fire tv stick" : 24.99
  }
}

Primeramente tenemos que agregar la regla en la consola.

regla .value


Para ordenar los productos por su precio, podemos realizar la siguiente consulta.


# Importamos las bibliotecas necesarias.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia o rama donde se guardarán los datos
ref = db.reference('Productos')

# realizamos la consulta por order_by_value()
consulta= ref.order_by_value().get()
for clave, valor in consulta.items():
    print(f"Producto: {clave} -> precio: {valor}")
Salida:

(miEntorno) chema@ubuntu:~/Cursos/Python/firebase$ python inicio.py
Producto: fire tv stick -> precio: 24.99
Producto: echo dot -> precio: 34.99
Producto: blink outdoor -> precio: 64.99

Consultas Complejas.


Ahora que hemos visto los puntos anteriores estamos en condiciones de usar los métodos de límite o rango que veremos a continuación para realizar consultas más complejas. Todos los métodos siguientes hay que utilizarlos usándolos con un método de los vistos anteriormente:

order_by_child()order_by_key() u order_by_value()

Consultas por límite.


Las consultas limit_to_first() y limit_to_last() se usan para establecer una cantidad máxima de elementos secundarios que se nos devolverá al hacer una consulta. Veámoslo mediante un ejemplo. Si partimos de la base de datos:


{
  "Productos": {
    "blink outdoor" : 64.99,
    "echo dot" : 34.99,
    "fire tv stick" : 24.99
  }
}
y queremos que nos ordene los productos por precio y nos muestre los dos primeros productos solamente, podemos usar este código:

import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia o rama donde se guardarán los datos
ref = db.reference('Productos')

consulta= ref.order_by_value().limit_to_first(2).get()
for clave, valor in consulta.items():
    print(f"Producto: {clave} -> precio: {valor}")
La salida es un diccionario ordenado con los dos valores que le hemos pedido.

chema@ubuntu:~/Cursos/Python/firebase$ python inicio.py
Producto: fire tv stick -> precio: 24.99
Producto: echo dot -> precio: 34.99

Sin embargo, si en lo que estamos interesados es en ver los dos últimos usaríamos el método limit_to_last(2)

import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia o rama donde se guardarán los datos
ref = db.reference('Productos')

consulta= ref.order_by_value().limit_to_last(2).get()
for clave, valor in consulta.items():
    print(f"Producto: {clave} -> precio: {valor}")
Salida:

chema@ubuntu:~/Cursos/Python/firebase$ python inicio.py
Producto: echo dot -> precio: 34.99
Producto: blink outdoor -> precio: 64.99

Consultas por Rango.



Con start_at(), end_at() y equal_to() podemos seleccionar los valores de comienzo o fin de nuestras consultas. Si en el ejemplo anterior queremos saber que artículos superan los 50 € podemos utilizar start_at() para conseguirlo.

import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia o rama donde se guardarán los datos
ref = db.reference('Productos')

consulta= ref.order_by_value().start_at(50).get()
for clave, valor in consulta.items():
    print(f"Producto: {clave} -> precio: {valor}")
Resultado:

chema@ubuntu:~/Cursos/Python/firebase$ python inicio.py
Producto: blink outdoor -> precio: 64.99

Podemos usar cualquiera de estos métodos no solo con valores numéricos. También las palabras se ordenan por orden alfabético. Por ejemplo podemos usar end_at() para obtener los productos que por orden alfabético antecedan a un determinado valor. Si usamos end_at("echo dot") nos dará todos los productos que ordenados alfabéticamente estén antes de este, incluido el mismo. En nuestro ejemplo solo "blink outdoor".

import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia o rama donde se guardarán los datos
ref = db.reference('Productos')

consulta= ref.order_by_key().end_at('echo dot').get()
for clave, valor in consulta.items():
    print(f"Producto: {clave} -> precio: {valor}")
Salida:

chema@ubuntu:~/Cursos/Python/firebase$ python inicio.py
Producto: blink outdoor -> precio: 64.99
Producto: echo dot -> precio: 34.99
También podemos combinar ambos métodos para establecer un rango de consultas. Por ejemplo si queremos saber todos los productos que alfabéticamente estén entre la "a" y la "c"

import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia o rama donde se guardarán los datos
ref = db.reference('Productos')

consulta= ref.order_by_key().start_at('a').end_at('c').get()
for clave, valor in consulta.items():
    print(f"Producto: {clave} -> precio: {valor}")
Salida:

chema@ubuntu:~/Cursos/Python/firebase$ python inicio.py
Producto: blink outdoor -> precio: 64.99

El método equal_to() te permite filtrar por coincidencias exactas. Esto es importante ya que nos permite encontrar coincidencias exactas en los registros. Por ejemplo si queremos saber cuanto cuesta un "fire tv stick":

# Importamos las bibliotecas necesarias.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia o rama donde se guardarán los datos
ref = db.reference('Productos')

consulta= ref.order_by_key().equal_to("fire tv stick").get()
for clave, valor in consulta.items():
Salida:

chema@ubuntu:~/Cursos/Python/firebase$ python inicio.py
Producto: fire tv stick -> precio: 24.99

Borrar registros. 


Borrar registros es sencillo. Solamente tendremos que ir al nodo que queremos borrar y ejecutar el método delete().  Si en la base de datos que hemos estado utilizando queremos borrar el producto "echo dot" podemos utilizar el siguiente código:

# Importamos las bibliotecas necesarias.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

# Cargo el certificado de mi proyecto Novatillo
cred = credentials.Certificate("novatillo-874ab-firebase-adminsdk-frqen-29438715e3.json")

# hace referencia a la base de datos en tiempo real que tenemos creada.
firebase_admin.initialize_app(cred, {'databaseURL':'https://novatillo-874ab-default-rtdb.europe-west1.firebasedatabase.app/'})

# Señalamos la referencia o rama donde se guardarán los datos
ref = db.reference('Productos')

consulta= ref.child("echo dot").delete()
veremos como ese nodo ha desaparecido de la base:

base de datos con registro borrrado


Para obtener más información sobre los métodos de Python aplicables en Firebase puedes seguir el siguiente enlace o este otro para saber más sobre las reglas de seguridad.


No hay comentarios:

Publicar un comentario