IndexedDb
Almacenamiento (de verdad) en local en HTML5
Eduard Tomàs
Developer @ Plain Concepts – http://plainconcepts.com
@eiximenis
Escuela IT - http://escuela.it
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
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)
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”
Abrir una BBDD
• Método open de window.IndexedDB
• Devuelve una request
• oncomplete
• En evt.target.result tenemos la BBDD (objecto IDBDatabase)
• onerror
Borrar una BBDD
• El método deleteDatabase del objeto indexedDB borra una base de
datos
• indexedDB.deleteDatabase(“my-db”).onsuccess = function(evt) {...}
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.
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.
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”)
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
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”)
Añadir datos
• Llamada al método add del objectstore
• Eso devuelve una request (asíncrono)
• Gestionar los eventos
• onsuccess
• onerror
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
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;}
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;}
Lectura de datos - cursores
• cursor.value -> Valor actual del cursor
• cursor.continue() -> Avanza al siguiente elemento
• cursor.advance() -> Avanza al siguiente elemento n veces
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)
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
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.
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
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)
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) {...}
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) {...}

JavaScript - HTML5 - IndexedDb

  • 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 • IndexedDbusa 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 • Cuandola 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 • Endicho 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 • Lapropiedad 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 • Obteneruna 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 • Losdatos 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 • Llamadaal 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 RangoCode 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étododelete(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 • Elmé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) {...}