Tengo una estructura de datos hecha de esta manera:
Y estoy configurando una función en la nube para cambiar todos los documentos de Publicaciones (subcolección) en un determinado evento, y para hacerlo, estoy usando consultas de collectionGroup
:
Así es como lo configuro:
exports.changeIsVisibleFieldAfterDay = functions.pubsub .schedule("every 2 minutes").onRun((context) => { const querySnapshot = db.collectionGroup("Posts") .where("isVisible", "==", true).get(); querySnapshot.forEach((doc) => { console.log(doc.data()); }); });
En el Firebase Log
recibo el siguiente error:
TypeError: querySnapshot.forEach is not a function
Buscando en línea descubrí que puede haber un problema con la versión SDK de Firebase pero la mía está actualizada, adjunto el archivo package.json
aquí:
{ "name": "functions", "description": "Cloud Functions for Firebase", "scripts": { "lint": "eslint .", "serve": "firebase emulators:start --only functions", "shell": "firebase functions:shell", "start": "npm run shell", "deploy": "firebase deploy --only functions", "logs": "firebase functions:log" }, "engines": { "node": "12" }, "main": "index.js", "dependencies": { "firebase-admin": "^9.2.0", "firebase-functions": "^3.11.0" }, "devDependencies": { "eslint": "^7.6.0", "eslint-config-google": "^0.14.0", "firebase-functions-test": "^0.2.0" }, "private": true }
El método get()
es asíncrono , por lo que debe usar then()
para obtener la querySnapshot
de consulta cuando se cumpla la Promesa devuelta por get()
, o usar async/await
. Más detalles sobre cómo lidiar con llamadas asincrónicas en esta respuesta SO .
then()
const functions = require('firebase-functions'); // The Firebase Admin SDK to access Firestore. const admin = require('firebase-admin'); admin.initializeApp(); const db = admin.firestore(); exports.changeIsVisibleFieldAfterDay = functions.pubsub .schedule("every 2 minutes").onRun((context) => { return db.collectionGroup("Posts").where("isVisible", "==", true).get() .then(querySnapshot => { querySnapshot.forEach((doc) => { console.log(doc.data()); }); return null; }) });
async/await
const functions = require('firebase-functions'); // The Firebase Admin SDK to access Firestore. const admin = require('firebase-admin'); admin.initializeApp(); const db = admin.firestore(); exports.changeIsVisibleFieldAfterDay = functions.pubsub .schedule("every 2 minutes").onRun(async (context) => { const querySnapshot = await db.collectionGroup("Posts").where("isVisible", "==", true).get(); querySnapshot.forEach((doc) => { console.log(doc.data()); }); return null; });
Tenga en cuenta el return null;
al final. Consulte este elemento de documento para obtener más detalles sobre este punto clave.
Tenga en cuenta también que si desea actualizar varios documentos dentro del forEach()
, deberá usar Promise.all()
. Muchas respuestas SO cubren este caso.