¿Por qué contar el número de documentos en una colección de Firebase?
En una aplicación Flutter, puede ser útil conocer el número de documentos presentes en una colección de Firebase. Por ejemplo, si deseas seleccionar un documento al azar, primero debes conocer el tamaño de la lista de documentos para definir un intervalo.
Hacer esto es relativamente sencillo si el número de documentos permanece constante día a día, pero ¿qué sucede si este número cambia? No podrás utilizar un intervalo fijo y modificarlo manualmente con cada nuevo documento puede ser tedioso y consumir tiempo valioso. Otra solución sería contar los documentos en tu lista con cada consulta. Sin embargo, esto puede ser no solo lento y costoso en términos de tiempo de ejecución, sino también más caro, ya que cada lectura de Firebase tiene un costo asociado.
Una solución óptima consiste en usar una Cloud Function para calcular el número de documentos en tus listas desde el backend y almacenar esta información en un lugar fácilmente accesible para tu aplicación.
Contar documentos en intervalos fijos
Una primera forma de implementar una función cloud para contar documentos es programarla para ejecutarse a intervalos regulares, como cada 24 horas.
Si aún no lo has hecho, primero deberás configurar las funciones cloud para tu proyecto Flutter.
Aquí tienes una forma sencilla de configurar una función programada para contar el número de documentos en una colección de Firebase:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
const db = admin.firestore();
exports.countDocumentsScheduled = functions.pubsub.schedule("every 24 hours").onRun(async (context) => {
try {
const collectionName = "your_collection_name"; // Reemplaza con el nombre de tu colección
// Recupera todos los documentos de la colección
const docsSnapshot = await db.collection(collectionName).get();
// Cuenta los documentos
const count = docsSnapshot.size;
// Almacena el resultado en un documento específico
await db.collection("metadata").doc("documentCount").set({
count: count,
lastUpdated: admin.firestore.FieldValue.serverTimestamp()
});
console.log(`Número de documentos en ${collectionName}: ${count}`);
} catch (error) {
console.error("Error al contar los documentos:", error);
}
});
Cada 24 horas, a partir del momento en que se despliega la función, la Cloud Function recorrerá tu colección para contar el número de documentos. El resultado se almacenará en el documento que hayas definido.
Existen muchos otros intervalos que puedes programar para activar tu función. Por ejemplo:
every 1 hours
: Cada hora.every 30 minutes
: Cada 30 minutos.2:00
: Todos los días a las 2:00 a.m.every monday 09:00
: Todos los lunes a las 9:00 a.m.1 of month 00:00
: Cada mes, el día 1 a las 00:00.every weekday 18:00
: Todos los días laborables a las 18:00, etc.
Llamar a la función de conteo desde Flutter
Otra forma de activar tu función es llamarla cuando el usuario haga clic en un botón dentro de tu aplicación Flutter.
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
const db = admin.firestore();
exports.countDocumentsOnRequest = functions.https.onRequest(async (req, res) => {
try {
const collectionName = req.query.collectionName || "your_collection_name"; // Cambia por el nombre de tu colección
// Verifica que el método sea GET
if (req.method !== "GET") {
return res.status(405).send("Método no permitido. Usa una solicitud GET.");
}
// Recupera todos los documentos de la colección
const docsSnapshot = await db.collection(collectionName).get();
// Cuenta los documentos
const count = docsSnapshot.size;
// Almacena el resultado en un documento específico
await db.collection("metadata").doc("documentCount").set({
count: count,
lastUpdated: admin.firestore.FieldValue.serverTimestamp(),
});
console.log(`Número de documentos en ${collectionName}: ${count}`);
// Responde con el conteo de documentos
res.status(200).json({ count });
} catch (error) {
console.error("Error al contar los documentos:", error);
res.status(500).send("Error interno del servidor.");
}
});
Cada vez que el usuario llame a esta función desde la interfaz de la aplicación Flutter, la Cloud Function calculará el número de documentos en la colección indicada.
En el frontend de Flutter, puedes usar esta función de la siguiente manera:
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<int> fetchDocumentCount(String collectionName) async {
try {
final url = Uri.parse("https://url_de_tu_funcion"); // Reemplaza con la URL de tu función en Cloud Function
final response = await http.get(url);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
return data['count'] ?? 0;
} else {
throw Exception("Error: ${response.statusCode}");
}
} catch (e) {
print("Error al llamar a la Cloud Function: $e");
return 0;
}
}
Contar documentos en Firebase tras un evento
Finalmente, otra forma de activar tu función es hacerlo durante un evento, como cuando se registra un usuario o se añade un nuevo documento.
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
const db = admin.firestore();
exports.updateDocumentCountOnWrite = functions.firestore
.document("your_collection_name/{docId}")
.onWrite(async (change, context) => {
try {
const collectionName = "your_collection_name";
// Recupera todos los documentos de la colección
const docsSnapshot = await db.collection(collectionName).get();
// Cuenta los documentos
const count = docsSnapshot.size;
// Almacena el resultado en un documento específico
await db.collection("metadata").doc("documentCount").set({
count: count,
lastUpdated: admin.firestore.FieldValue.serverTimestamp()
});
console.log(`Número de documentos en ${collectionName}: ${count}`);
} catch (error) {
console.error("Error al actualizar el conteo de documentos:", error);
}
});
Esta función se activa cada vez que se añade, modifica o elimina un documento en la colección especificada (your_collection_name/{docId}
). Solo necesitas personalizar esta parte según tus necesidades.