Skip to content

Latest commit

 

History

History
596 lines (460 loc) · 22 KB

File metadata and controls

596 lines (460 loc) · 22 KB

shieldsIO shieldsIO shieldsIO

WideImg

Máster en Programación FullStack con JavaScript y Node.js

JS, Node.js, Frontend, Backend, Firebase, Express, Patrones, HTML5_APIs, Asincronía, Websockets, Testing

Clase 85

Cloud Firestore

logo

Usa nuestra base de datos NoSQL flexible, escalable y en la nube a fin de almacenar y sincronizar datos para la programación en el lado del cliente y del servidor. Cloud Firestore

Estrategia de desarrollo

  • Integra los SDK de Cloud Firestore
  • Protege los datos
  • Agrega datos
  • Obtén datos

Recursos

Cloud Firestore: Claves

promo_banner

Flexibilidad

El modelo de datos de Cloud Firestore admite estructuras de datos flexibles y jerárquicas. Almacena tus datos en documentos, organizados en colecciones. Los documentos pueden contener objetos anidados complejos, además de subcolecciones.

Consultas expresivas

En Cloud Firestore, puedes usar consultas para recuperar documentos individuales específicos o para recuperar todos los documentos de una colección que coinciden con los parámetros de la consulta. Tus consultas pueden incluir varios filtros en cadena y combinar los filtros con criterios de orden. También se indexan de forma predeterminada, por lo que el rendimiento de las consultas es proporcional al tamaño de tu conjunto de resultados, no del conjunto de datos.

Actualizaciones en tiempo real

Al igual que Realtime Database, Cloud Firestore usa la sincronización de datos para actualizar los datos de cualquier dispositivo conectado. Sin embargo, también está diseñado para ejecutar consultas de recuperación únicas y sencillas de manera eficiente.

Asistencia sin conexión

Cloud Firestore almacena en caché datos que usa tu app de forma activa, por lo que la app puede escribir, leer, escuchar y consultar datos, aunque el dispositivo se encuentre sin conexión. Cuando el dispositivo vuelve a estar en línea, Cloud Firestore sincroniza todos los cambios locales de vuelta a Cloud Firestore.

Diseñado para ajustarse a escala

Cloud Firestore te ofrece lo mejor de la poderosa infraestructura de Google Cloud Platform: replicación automática de datos multirregión, garantías de coherencia sólida, operaciones atómicas por lotes y asistencia real sobre transacciones. Diseñamos Cloud Firestore para controlar las cargas de trabajo de las bases de datos más complejas de las apps más grandes del mundo.

Cloud Firestore: Los datos

Terminología

promo_banner

Las colecciones

promo_banner

Cloud Firestore: Lo Básico para Browser

Agrega Cloud Firestore al proyecto

<script src="https://www.gstatic.com/firebasejs/4.12.1/firebase.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.12.1/firebase-firestore.js"></script>

Inicializa Cloud Firestore

firebase.initializeApp({
  apiKey: '### FIREBASE API KEY ###',
  authDomain: '### FIREBASE AUTH DOMAIN ###',
  projectId: '### CLOUD FIRESTORE PROJECT ID ###'
});

// Initialize Cloud Firestore through Firebase
var db = firebase.firestore();

Agrega datos

db.collection("users").add({
    first: "Ada",
    last: "Lovelace",
    born: 1815
})
.then(function(docRef) {
    console.log("Document written with ID: ", docRef.id);
})
.catch(function(error) {
    console.error("Error adding document: ", error);
});

Lee datos

db.collection("users").get().then((querySnapshot) => {
    querySnapshot.forEach((doc) => {
        console.log(`${doc.id} => ${doc.data()}`);
    });
});

Cloud Firestore: Lo Básico para Nodejs

Agrega Cloud Firestore al proyecto

npm install firebase@4.12.1 --save
const firebase = require("firebase");
require("firebase/firestore"); // Required for side-effects

Inicializar en Cloud Functions

const admin = require('firebase-admin');
const functions = require('firebase-functions');

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

var db = admin.firestore();

Inicializar en Google Cloud Platform

const admin = require('firebase-admin');

admin.initializeApp({
  credential: admin.credential.applicationDefault()
});

var db = admin.firestore();

Inicializar en tu propio servidor

const admin = require('firebase-admin');

var serviceAccount = require('path/to/serviceAccountKey.json');

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount)
});

var db = admin.firestore();

Agrega datos

var docRef = db.collection('users').doc('alovelace');

var setAda = docRef.set({
  first: 'Ada',
  last: 'Lovelace',
  born: 1815
});

Lee datos

db.collection('users').get()
    .then((snapshot) => {
      snapshot.forEach((doc) => {
        console.log(doc.id, '=>', doc.data());
      });
    })
    .catch((err) => {
      console.log('Error getting documents', err);
    });

Cloud Firestore: Agregar y administrar datos

Claves

  • Cada documento contiene un conjunto de pares clave-valor.
  • Todos los documentos se deben almacenar en colecciones.
  • Los documentos pueden contener subcolecciones y objetos anidados, y ambos pueden incluir campos primitivos como strings o tipos de objetos complejos como listas.
  • Las colecciones y los documentos se crean de manera implícita
  • El tamaño máximo de un documento es 1 MB
  • Las colecciones son como las tablas de SQL
  • Los documentos son como las filas de una tabla de SQL
  • Los objetos complejos anidados en un documento se llaman mapas.
  • Cloud Firestore admite diversos tipos de datos para los valores: booleanos, números, strings, puntos geográficos, BLOB binarios y marcas de tiempo.Además, puedes usar arreglos u objetos anidados, llamados mapas, para estructurar datos dentro de un documento.
  • Cuando se crea el primer documento de una colección, esta pasa a existir. Si borras todos los documentos de una colección, esta deja de existir.

Referencias a colecciones

var usersCollectionRef = db.collection('users');

Referencias a documentos

var alovelaceDocumentRef = db.collection('users').doc('alovelace');
var alovelaceDocumentRef = db.doc('users/alovelace');

Datos jerárquicos (Subcolecciones)

esquema

  • Puedes anidar datos hasta 100 niveles de profundidad.
  • Cuando borras un documento que tiene subcolecciones asociadas, las subcolecciones no se borran. Se puede seguir accediendo a ellas mediante una referencia
var messageRef = db.collection('rooms').doc('roomA')
                .collection('messages').doc('message1');

Estructuras de datos

  • Datos anidados en documentos Puedes anidar objetos complejos como matrices (mapas) dentro de los documentos.
  • Subcolecciones Puedes crear colecciones dentro de los documentos cuando tengas datos que podrían expandirse con el tiempo.
  • Colecciones de nivel de raíz Crea colecciones de nivel de raíz de tu base de datos para organizar los conjuntos de datos dispares.

Tipos de datos

  • Matriz. Ordenación por elementos y, si los elementos son iguales, por longitud de matriz [1, 2, 3] < [1, 2, 3, 1] < [2].
  • Booleano
  • Bytes Hasta 1,048,487 bytes (de 1 MiB a 89 bytes). Las consultas solo consideran los primeros 1,500 bytes.
  • Fecha y hora La precisión máxima es de microsegundos; cualquier precisión adicional se redondea hacia abajo.
  • Número de coma flotante Precisión doble de 64 bits, IEEE 754.
  • Punto geográfico Por latitud, luego por longitud
  • Entero 64 bits, firmado
  • Mapa Representa un objeto incorporado en un documento.
  • Nulo
  • Referencia Por ejemplo projects/[PROJECT_ID]/databases/[DATABASE_ID]/documents/[DOCUMENT_PATH]
  • String de texto Hasta 1,048,487 bytes (de 1 MiB a 89 bytes). Las consultas solo consideran los primeros 1,500 bytes de la representación UTF-8.

Cloud Firestore: Agregar datos

Claves

  • Cloud Firestore admite operaciones atómicas para la lectura y la escritura de datos. En un conjunto de operaciones atómicas, todas las operaciones se aplican de manera correcta o no se aplica ninguna de ellas.
  • Transacciones conjunto de operaciones de lectura y de escritura en uno o más documentos
  • Escrituras en lotes conjunto de operaciones de escritura en uno o más documentos
  • Cada transacción o escritura en lote puede escribir en un máximo de 500 documentos.
  • Cloud Firestore siempre almacena los números como dobles, independientemente del tipo de número que uses en tu código.

set() Para crear o sobrescribir un solo documento

// Add a new document in collection "cities"
db.collection("cities").doc("LA").set({
    name: "Los Angeles",
    state: "CA",
    country: "USA"
})
.then(function() {
    console.log("Document successfully written!");
})
.catch(function(error) {
    console.error("Error writing document: ", error);
});
/*
Si el documento no existe, se creará. 
Si el documento existe, su contenido se sobrescribirá con los datos proporcionados, 
a menos que especifiques que los datos se deberían combinar en el documento existente, 
de la siguiente manera:
*/
var cityRef = db.collection('cities').doc('BJ');

var setWithMerge = cityRef.set({
    capital: true
}, { merge: true });

add() Es como set() pero no necesitas especificar el ID, que se genera automáticamente

const data = {
    name: "Tokyo",
    country: "Japan"
};

// con set()
db.collection("cities").doc("new-city-id").set(data);


// con add()
db.collection("cities").add(data)
.then(function(docRef) {
    console.log("Document written with ID: ", docRef.id);
})
.catch(function(error) {
    console.error("Error adding document: ", error);
});

update() Actualiza algunos campos de un documento sin sobrescribir todo el documento

var washingtonRef = db.collection("cities").doc("DC");

// Set the "capital" field of the city 'DC'
return washingtonRef.update({
    capital: true
})
.then(function() {
    console.log("Document successfully updated!");
})
.catch(function(error) {
    // The document probably doesn't exist.
    console.error("Error updating document: ", error);
});
/* 
-- Actualiza los campos en objetos anidados --
*/

// Create an initial document to update.
var frankDocRef = db.collection("users").doc("frank");
frankDocRef.set({
    name: "Frank",
    favorites: { food: "Pizza", color: "Blue", subject: "recess" },
    age: 12
});

// To update age and favorite color:
db.collection("users").doc("frank").update({
    "age": 13,
    "favorites.color": "Red"
})
.then(function() {
    console.log("Document successfully updated!");
});
/* 
-- Actualiza el timestamp por consulta --
*/
var docRef = db.collection('objects').doc('some-id');

// Update the timestamp field with the value from the server
var updateTimestamp = docRef.update({
    timestamp: firebase.firestore.FieldValue.serverTimestamp()
});

Cloud Firestore: Borrar Datos

delete() Para borrar un documento

db.collection("cities").doc("DC").delete().then(function() {
    console.log("Document successfully deleted!");
}).catch(function(error) {
    console.error("Error removing document: ", error);
});

FieldValue.delete() Para borrar campos específicos de un documento

var cityRef = db.collection('cities').doc('BJ');

// Remove the 'capital' field from the document
var removeCapital = cityRef.update({
    capital: firebase.firestore.FieldValue.delete()
});

Borrar Colecciones

⚠️ Para borrar por completo una colección o subcolección en Cloud Firestore, recupera todos los documentos de la colección o subcolección y bórralos. Si tienes colecciones más grandes, te recomendamos borrar los documentos en grupos pequeños para evitar errores de memoria insuficiente. Repite el proceso hasta que borres toda la colección o subcolección.

⚠️ Para borrar una colección, se debe coordinar una cantidad ilimitada de solicitudes de eliminación individuales. Si necesitas borrar colecciones completas, hazlo únicamente desde un entorno de servidor de confianza. Si bien es posible borrar una colección desde un cliente web o para dispositivos móviles, tiene efectos negativos en el rendimiento y en la seguridad.

Cloud Firestore: Recuperar datos

get() Recupera los datos

/*
-- cómo recuperar los contenidos de un documento --
*/
var docRef = db.collection("cities").doc("SF");

docRef.get().then(function(doc) {
    if (doc.exists) {
        console.log("Document data:", doc.data());
    } else {
        // doc.data() will be undefined in this case
        console.log("No such document!");
    }
}).catch(function(error) {
    console.log("Error getting document:", error);
});

/*
Si no hay un documento en la ubicación a la que hace referencia docRef, 
el document resultante estará vacío y si se llama a exists se mostrará false.
*/
/*
-- Obtén todos los documentos de una colección --
*/
db.collection("cities").get().then(function(querySnapshot) {
    querySnapshot.forEach(function(doc) {
        // doc.data() is never undefined for query doc snapshots
        console.log(doc.id, " => ", doc.data());
    });
});

onSnapshot() Mantenerse escuchando cambios

db.collection("cities").doc("SF")
    .onSnapshot(function(doc) {
        console.log("Current data: ", doc.data());
    });
/*
-- Escucha varios documentos en una colección --
*/
db.collection("cities").where("state", "==", "CA")
    .onSnapshot(function(querySnapshot) {
        var cities = [];
        querySnapshot.forEach(function(doc) {
            cities.push(doc.data().name);
        });
        console.log("Current cities in CA: ", cities.join(", "));
    });
/*
-- Desvincula un agente de escucha --
*/
var unsubscribe = db.collection("cities")
    .onSnapshot(function () {});
// ...
// Stop listening to changes
unsubscribe();

Cloud Firestore: Queries y ordenación

Limitaciones de las consultas

  • Consultas con filtros de rango en diferentes campos: citiesRef.where("state", ">=", "CA").where("population", ">", 100000)
  • Consultas únicas que se ejecutan en varias colecciones o subcolecciones. Cada consulta se ejecuta en una sola colección de documentos Doc: selección de una estructura de datos
  • Consultas de miembros individuales de un arreglo. Doc: Cómo trabajar con arreglos, listas y conjuntos.
  • Consultas con el operador lógico OR. En este caso, deberías crear una consulta independiente para cada condición de OR y combinar los resultados de la consulta en tu app.
  • Consultas con una cláusula !=. La solución para where("age", "!=", "30") es where("age", ">", 30) y where("age", "<", "30")
  • Filtro de rango y primer orderBy en campos distintos citiesRef.where("population", ">", 100000).orderBy("country")

where() hacer una consulta que busque todos los documentos que cumplan una condición determinada

  • Usa tres parámetros: un campo para filtrar, una operación de comparación y un valor.
  • La comparación puede ser <, <=, ==, > o >=
db.collection("cities").where("capital", "==", true)
    .get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            // doc.data() is never undefined for query doc snapshots
            console.log(doc.id, " => ", doc.data());
        });
    })
    .catch(function(error) {
        console.log("Error getting documents: ", error);
    });
citiesRef.where("state", "==", "CA")
citiesRef.where("population", "<", 100000)
citiesRef.where("name", ">=", "San Francisco")

orderBy() Define el orden en el que se presentan los datos

/*
-- ordenar por estado y, dentro de cada estado, por población de manera descendente --
*/
citiesRef.orderBy("state").orderBy("population", "desc")

limit() limita la cantidad de documentos que se recuperan.

//las últimas 3 ciudades en orden ascendente
citiesRef.orderBy("name").limit(3)

//las últimas 3 ciudades en orden descendente
citiesRef.orderBy("name", "desc").limit(3) 

💪 Combinación

citiesRef.where("population", ">", 100000).orderBy("population").limit(2)

Cloud Firestore: Paginación

Claves

  • Usar startAt() o startAfter() para definir el punto de inicio de una consulta
  • El método startAfter() lo excluye

Ejemplo simple

var first = db.collection("cities")
        .orderBy("population")
        .limit(25);

return first.get().then(function (documentSnapshots) {
  // Get the last visible document
  var lastVisible = documentSnapshots.docs[documentSnapshots.docs.length-1];
  console.log("last", lastVisible);

  // Construct a new query starting at this document,
  // get the next 25 cities.
  var next = db.collection("cities")
          .orderBy("population")
          .startAfter(lastVisible)
          .limit(25);
});

Cloud Firestore: Índices

Los índices son un factor importante del rendimiento de las bases de datos. Al igual que el índice de un libro que indica en qué página se encuentra cada tema, el índice de una base de datos se encarga de ordenar todos los elementos en su ubicación respectiva. Cuando envías una consulta a una base de datos, esta puede usar el índice para buscar rápidamente los elementos que solicitaste

Claves

Cloud Firestore: Otros

Importante

Ejemplo

Friendly Eats

Esta app de ejemplo demuestra la compilación de un servicio simple de recomendación de restaurantes con Cloud Firestore. Permite demostrar funciones como las consultas compuestas, las transacciones del cliente, las subcolecciones y la persistencia sin conexión.

Ejercicios

1 - Ejercicio de server render con MovieFire (Firestore)

// Tu solución

2 - Ejercicio de APIRest con MovieFire (Firestore)

// Tu solución