IndexedDb es una API HTML5 para guardar datos en local. A diferencia de localStorage, IndexedDb es muy rápida, permite búsquedas y es válida para grandes cantidades de datos.
1. IndexedDb
Almacenamiento (de verdad) en local en HTML5
Eduard Tomàs
Developer @ Plain Concepts – http://plainconcepts.com
@eiximenis
Escuela IT - http://escuela.it
2. Qué es IndexedDb
• Almacenamiento de datos en local
• No relacional (nada de “tablas”, “joins” o “SQL”)
• Almacena objetos JavaScript
• Rápido y válido para grandes volúmenes de datos
3. Conceptos IndexedDb
• IndexedDb usa almacenamiento (clave, valor)
• Todas las operaciones son transaccionales
• La API es totalmente asíncrona
• Las peticiones asíncronas se modelan como objetos “request”
• Los objetos “request” usan eventos DOM para comunicar éxito o
fallo.
• Los valores de IndexedDb son objetos JavaScript
• Es un modelo no-relacional (no SQL)
4. Base de Datos
• Una base de datos contiene uno o más almacenes de objetos.
• Tiene un nombre y una versión
• IndexedDb está preparado para “cambios de esquema”
• Las BBDD son durables*
* Bueno... “casi durables”
5. Abrir una BBDD
• Método open de window.IndexedDB
• Devuelve una request
• oncomplete
• En evt.target.result tenemos la BBDD (objecto IDBDatabase)
• onerror
6. Borrar una BBDD
• El método deleteDatabase del objeto indexedDB borra una base de
datos
• indexedDB.deleteDatabase(“my-db”).onsuccess = function(evt) {...}
7. Evento onupgradeneeded
• Cuando la versión local de la BBDD no coincide con la solicitada se
ejecuta este evento.
• En evt.target.result tenemos la BBDD (objecto IDBDatabase)
• Aquí debemos crear todos los almacenes necesarios según la
versión indicada.
8. Evento onupgradeneeded
• En dicho evento no tenemos que recrearla toda en este evento.
• Solo los cambios necesarios para pasar a la versión pedida.
• La función gestora de onupgradeneeded debe estar preparada
para preguntar “qué hay en la BBDD” y actualizar lo que falte
de almacenes y índices.
9. Evento onupgradeneeded
• La propiedad objectStoreNames de la base de datos devuelve los
nombres de todos los object stores existentes.
• Para obtener un objectStore debemos hacerlo a través de la
transacción de upgrade
• var store = evt.currentTarget.transaction.o bjectStore(“xxx”)
10. Crear almacenes
• Obtener una referencia a la BBDD
• Usar método createObjectStore(“nombre”, opciones)
• Opciones contiene keyPath o autoIncrement
• keyPath: ‘name’ -> Establece name como la propiedad indexada (única)
• autoIncrement: ‘id’ -> Establece id como una propiedad autoincremental
createObjectStore("note", { keyPath: "id", autoIncrement:true });
• Eso devuelve una referencia al object store
11. Añadir datos
• Los datos se añaden a un almacen
• Debe crearse una transacción
• db.transaction(stores, mode)
• stores -> String con nombre de store o array con nombre de n stores
• Mode
• readonly
• readwrite
• readwriteFlush (FF only)
• Una vez se tiene la Tx se obtiene el objectstore con tx.objectstore(“name”)
12. Añadir datos
• Llamada al método add del objectstore
• Eso devuelve una request (asíncrono)
• Gestionar los eventos
• onsuccess
• onerror
13. Errores en transacciones
• Los eventos de IndexedDB “fluyen” hacia arriba
• Si hay un error insertando un dato
• Se ejecuta onerror de la request correspondiente
• Se ejecuta onerror de la transacción correspondiente
• Se ejecuta onerror de la bbdd correspondiente
14. Lectura de datos
• Se realiza también en el contexto de una transacción
• Se usa el método get del almacén para obtener el elemento
asociado a una clave
• El método get devuelve una request (onsuccess, onerror)
• db.transaction(“store”).objectstore(“store”).get(“key-value”).onsuccess =
function(evt) { var data = evt.target.value;}
15. Lectura de datos - cursores
• El cursor se usa para iterar sobre los elementos de un almacén
• Se obtiene a partir del método openCursor de un almacén
• El método openCurso devuelve una request
• Siempre dentro del contexto de una transacción
• var r = db.transaction(“store”).objectStore(“store”).openCursor();
• r.onsuccess = function(evt) { var c = event.target.result;}
16. Lectura de datos - cursores
• cursor.value -> Valor actual del cursor
• cursor.continue() -> Avanza al siguiente elemento
• cursor.advance() -> Avanza al siguiente elemento n veces
17. Lectura de datos - índices
• Para buscar a sobre los valores de una propiedad se requiere un
índice montado sobre esta propiedad
• El método createIndex del almacén permite definir un índice
sobre él.
• createIndex(name, path, options)
18. Lectura de datos - índices
• name -> Nombre del índice
• path -> Propiedad sobre la que se crea el índice
• options
• unique -> true / false (si el índice es único)
• multiEntry -> Si vale true permite operar con índices sobre arrays
19. Lectura de datos - índices
• El método index del objectStore permite obtener un índice
• store.index(“name”)
• El índice expone los métodos
• get -> Obtiene el elemento con el valor del índice indicado (único)
• openCursor -> Obtiene un cursor que itera sobre los elementos del almacén
pero según el índice.
20. Cursores - Rangos
• El método openCursor puede recibir un rango como parámetro.
Eso devuelve un cursor que itera solamente dentro de ese rango.
• Para construir el rango se usa IDBKeyRange
21. Cursores - Rangos
Rango Code
Claves ≤ x IDBKeyRange.upperBound(x)
Claves < x IDBKeyRange.upperBound(x, true)
Claves ≥ y IDBKeyRange.lowerBound(y)
Claves > y IDBKeyRange.lowerBound(y, true)
Claves ≥ x && ≤ y IDBKeyRange.bound(x, y)
Claves > x &&< y IDBKeyRange.bound(x, y, true, true)
Claves > x && ≤ y IDBKeyRange.bound(x, y, true, false)
Claves ≥ x &&< y IDBKeyRange.bound(x, y, false, true)
Clave = z IDBKeyRange.only(z)
22. Eliminar datos
• Método delete(key) del objectStore elimina el objeto con la clave
indicada
• Como siempre, dentro del contexto de una transacción
• var req = db.transaction(“store”,
“readwrite”).objectStore(“store”).delete(key);
• req.onsuccess = function(evt) {...}
23. Modificar datos
• El método put del almacén permite modificar datos
• Como siempre... Dentro de una transacción ;-)
• var store = db.transaction(“store”).objectStore(“store”);
• store.put(data).onsuccess = function(evt) {...}