IndexedDB
IndexedDB es una base de datos de tipo NoSQL implementada en todos los navegadores modernos. Almacena los datos como objetos, de foma similar a otros gestores de bases de datos como MongoDB. Como la API de Web Storage, IndexedDB crea las bases de datos diferenciadas por origen (dominio:puerto) donde se está ejecutando una aplicación web. Solo podemos acceder a los datos del dominio asociado a la aplicación.
Esta base de datos no tiene las limitaciones de almacenamiento de Local Storage (unos 10MB). Aunque dependiendo del navegador, cuando una web excede de una cuota determinada (50MB en Chrome, por ejemplo), pedirá al usuario permiso para poder almacenar más información y sobrepasar ese límite.
IndexedDB trabaja con operaciones asíncronas, usando eventos para procesar las respuestas. Podemos englobar dichas operaciones en promesas para aprovechar sus ventajas, como la de concatenar operaciones.
La información se almacena dentro de almacenes de objetos (object stores), equivalentes tablas en SQL, aunque no es exactamente lo mismo. Los almacenes guardan parejas de clave-valor, pero al contrario que Local Storage, se almacenan objetos como valor en lugar de cadenas. La clave asociada a cada objeto puede ser autogenerada, o una propiedad del objeto (que no se repita). Sería equivalente a la clave primaria en una base de datos relacional.
Crear / Abrir una base de datos
Para leer o modificar una base de datos, debes abrirla primero llamando a IndexedDB.open. Esta operación es asíncrona y debemos manejar su resultado mediante los eventos correspondientes. El método recibe el nombre de la base de datos (string) y la versión (número entero). Estos son los eventos que pueden ocurrir:
- Si la base de datos no existe o la versión enviada es mayor que la existente, se lanzará un evento del tipo upgradeneeded. Es en este momento cuando podremos modificar la estructura de la base de datos y añadir o eliminar almacenes de objetos.
- Si la base de datos existe (o después de haberla creado / actualizado), se lanzará un evento de tipo success. A partir de aquí, podremos añadir, borrar y modificar objetos en los almacenes.
- Un evento de tipo error se lanzará cuando algo vaya mal.
- Si la base de datos ya está abierta (se abrió anteriormente sin cerrar la conexión), se lanza un evento blocked.
Vamos a ver como englobar todo esto dentro de una promesa, para gestionar todo lo arriba descrito en una única operación, que devolverá un objeto para manipular la base de datos si todo ha ido bien, o un error si algo falla:
Borrando una base de datos
Antes de borrar una base de datos, debemos asegurarnos de que está cerrada. Si la hemos abiero, podemos cerrarla llamando al método close(). En ese momento podremos usar indexedDB.deleteDatabase('nombre') para borrarla. Esta operación también es asíncrona.
Operaciones CRUD
Todas las operaciones CRUD (Create, Read, Update, Delete → Creación, Lectura, Actualización, Borrado) deben hacerse usando una transacción. Las transacciones se realizan en modo lectura (readonly) o escritura (readwrite). Las transacciones realizan sobre un almacén de objetos y devuelven un objeto del tipo IDBObjectStore, del cual usaremos sus métodos para las operaciones. Todas ellas son asíncronas. Ejemplos:
Obteniendo todos los objetos de un almacén
Obteniendo un objeto a partir de su clave
Insertando un objeto
Actualizando un objeto
Borrando un objeto
Creación de índices
Crear índices en los almacenes de objetos permite hacer búsquedas a partir de otros atributos del objeto diferentes a la clave elegida (clave primaria). Para ello podemos usar el método createIndex después de crear el almacén de objetos. Este método recibe 3 parámetros: nombre del índice, atributo del objeto (puede ser compuesto → array), y opciones (por ejemplo unique para campos que no admitan valores repetidos).
A partir del índice, cuando queramos hacer una operación de consulta, podremos crear rangos, y que nos devuelva resultados a partir de ciertos criterios de búsqueda. Por ejemplo: