Tengo un escenario en el que necesito consultar varias colecciones a la vez y recuperar los valores según el nombre de la colección. Uso Promise.all para hacerlo y funciona en consecuencia así
var dbPromises = []; dbPromises.push( admin.firestore().collection("collection1").where("user_id", "==", uid).get(), admin.firestore().collection("collection2").where("user_id", "==", uid).get(), admin.firestore().collection("collection3").where("user_id", "==", uid).get(), ); const promiseConst = await Promise.all(dbPromises); promiseConst.forEach((qs) => { if (qs.size > 0) { if (qs.query._queryOptions.collectionId == "collection1") { qs.docs.map((doc) => { valuesArr1.push(doc.data().arr); }); } else if (qs.query._queryOptions.collectionId == "Collection2") { qs.docs.map((doc) => { valuesArr2.push(doc.data()); }); } else if (qs.query._queryOptions.collectionId == "collection3") { qs.docs.map((doc) => { valuesArr3.push(doc.data()); }); } } else { return } }); for (var i=0; i < valuesArr1.length; i++) { if (valuesArr1[i].desiredData) { console.log('datas from for loop on datas array', valuesArr1[i].desiredData) globalVariable += `<img src="${valuesArr1[i].desiredData}">`; } }Una vez que hago esto, mapeo la instantánea de consulta que obtengo y puedo recuperar los valores hasta este punto así
De la primera colección, recupero una matriz de un documento de Firestore y luego las siguientes colecciones, solo recupero todos los documentos de las colecciones. Todo esto 'funciona' en el sentido de que cuando me consuelo.Inicio de sesión en la consola de funciones, los datos se muestran exactamente como se esperaba. Solo cuando quiero iterar sobre los datos y asignar los resultados a una variable global para usar en otro lugar, se produce un comportamiento extraño.
El console.log muestra los datos deseados en la consola de funciones sin problemas, pero el resultado cuando interpolo esos datos en el html y los envío en nodemailer obtengo el siguiente resultado
indefinido siempre es el primero en la respuesta cuando uso el operador de asignación de suma +=, pero si solo uso el operador de asignación = no hay indefinido, pero obviamente no obtengo todos los datos que espero.
No hay valores o documentos indefinidos en las colecciones que estoy recuperando, he revisado minuciosamente e incluso eliminé documentos para asegurarme de ello. Después de días de investigación, llegué a la conclusión de que tiene que ver con la naturaleza asincrónica de la promesa con la que estoy trabajando y que los datos no están listos de inmediato cuando los itero.
¿Alguien puede ayudarme a entender qué estoy haciendo mal y cómo solucionarlo en el nodo?
Encontré una solución a mi problema y me gustaría compartirla con la esperanza de que le ahorre tiempo a un futuro espectador.
Antes, almacenaba los resultados de la matriz de Firebase dentro de una variable global. Para evitar rascarse la cabeza, publicaré el código nuevamente a continuación.
var globalVariableArray = [] var globalVariable var dbPromises = []; dbPromises.push( admin.firestore().collection("DataCollection").where("user_id", "==", uid).get() ); const promiseConst = await Promise.all(dbPromises); promiseConst.forEach((qs) => { if (qs.size > 0) { if (qs.query._queryOptions.collectionId == "DataCollection") { Promise.all( qs.docs.map(doc => { globalVariableArray = doc.data().arrayWithDesiredData; }) ); } else { return } }); globalVariableArray.map(gv => { globalVariable += `<p>gv.desiredData</p>` // <--- Right here is where the problem area was }) var mailOptions = { from: foo@blurdybloop.com, to: 'bar@blurdybloop.com subject: 'Almost but not quite', html: `${globalVariable}` }; El código anterior da el resultado esperado, pero el resultado siempre tendría undefined primero antes de que se mostraran los datos. Esto sucedió sin importar cómo se iteró la matriz de Firebase.
Después de fortalecer mi Google-Fu, resolví la siguiente solución
var globalVariableArray = [] var globalVariable var dbPromises = []; dbPromises.push( admin.firestore().collection("DataCollection").where("user_id", "==", uid).get() ); const promiseConst = await Promise.all(dbPromises); promiseConst.forEach((qs) => { if (qs.size > 0) { if (qs.query._queryOptions.collectionId == "DataCollection") { Promise.all( qs.docs.map(doc => { globalVariableArray = doc.data().arrayWithDesiredData; }) ); } else { return } }); var mailOptions = { from: foo@blurdybloop.com, to: 'bar@blurdybloop.com subject: 'It works!!', html: `${globalVariableArray.map(dataIWantedAllAlong => <p>dataIWantedAllAlong.desiredData</p> )}` <--- Here I simply loop through the array inside the interpolation blocks and voila! no more undefined showing up in the results }; Realizo el ciclo dentro de los corchetes donde interpolo los datos dinámicos y ya no recibo ese molesto undefined que aparece en mis correos electrónicos.
¡Viajes seguros y feliz codificación para todos ustedes!