Me pregunto si es posible obtener varios documentos por lista de identificadores en un viaje de ida y vuelta (llamada de red) a Firestore.
Me pregunto si es posible obtener varios documentos por lista de identificadores en un viaje de ida y vuelta (llamada de red) a Firestore.
si estás dentro del nodo:
https://github.com/googleapis/nodejs-firestore/blob/master/dev/src/index.ts#L701
/**
* Retrieves multiple documents from Firestore.
*
* @param {...DocumentReference} documents - The document references
* to receive.
* @returns {Promise<Array.<DocumentSnapshot>>} A Promise that
* contains an array with the resulting document snapshots.
*
* @example
* let documentRef1 = firestore.doc('col/doc1');
* let documentRef2 = firestore.doc('col/doc2');
*
* firestore.getAll(documentRef1, documentRef2).then(docs => {
* console.log(`First document: ${JSON.stringify(docs[0])}`);
* console.log(`Second document: ${JSON.stringify(docs[1])}`);
* });
*/
Esto es específicamente para el SDK del servidor.
ACTUALIZACIÓN: "¡Cloud Firestore [sdk del lado del cliente] ahora admite consultas IN!"
https://firebase.googleblog.com/2019/11/cloud-firestore-now-supports-in-queries.html
myCollection.where(firestore.FieldPath.documentId(), 'in', ["123","456","789"])
firebase.firestore.FieldPath.documentId()
y no'id'
Acaban de anunciar esta funcionalidad, https://firebase.googleblog.com/2019/11/cloud-firestore-now-supports-in-queries.html .
Ahora puede usar consultas como, pero tenga en cuenta que el tamaño de entrada no puede ser mayor que 10.
userCollection.where('uid', 'in', ["1231","222","2131"])
db.collection('users').where(firebase.firestore.FieldPath.documentId(), 'in',["123","345","111"]).get()
firebase.firestore.FieldPath.documentId()
No, en este momento no hay forma de agrupar varias solicitudes de lectura con el SDK de Cloud Firestore y, por lo tanto, no hay forma de garantizar que pueda leer todos los datos a la vez.
Sin embargo, como ha dicho Frank van Puffelen en los comentarios anteriores, esto no significa que obtener 3 documentos será 3 veces más lento que obtener un documento. Es mejor realizar sus propias mediciones antes de llegar a una conclusión aquí.
En la práctica, usaría firestore.getAll así
async getUsers({userIds}) {
const refs = userIds.map(id => this.firestore.doc(`users/${id}`))
const users = await this.firestore.getAll(...refs)
console.log(users.map(doc => doc.data()))
}
o con sintaxis de promesa
getUsers({userIds}) {
const refs = userIds.map(id => this.firestore.doc(`users/${id}`))
this.firestore.getAll(...refs).then(users => console.log(users.map(doc => doc.data())))
}
Podrías usar una función como esta:
function getById (path, ids) {
return firestore.getAll(
[].concat(ids).map(id => firestore.doc(`${path}/${id}`))
)
}
Se puede llamar con un solo ID:
getById('collection', 'some_id')
o una serie de ID:
getById('collection', ['some_id', 'some_other_id'])
Sin duda, la mejor manera de hacerlo es implementando la consulta real de Firestore en una función de nube. Entonces solo habría una única llamada de ida y vuelta desde el cliente a Firebase, que parece ser lo que está pidiendo.
Realmente desea mantener toda su lógica de acceso a datos como este lado del servidor de todos modos.
Internamente, probablemente habrá la misma cantidad de llamadas a Firebase, pero todas serían a través de las interconexiones súper rápidas de Google, en lugar de la red externa, y combinadas con la canalización que Frank van Puffelen ha explicado, debería obtener un excelente rendimiento de Este enfoque.
Si está usando flutter, puede hacer lo siguiente:
Firestore.instance.collection('your collection name').where(FieldPath.documentId, whereIn:[list containing multiple document IDs]).getDocuments();
Esto devolverá un futuro List<DocumentSnapshot>
que contiene que puede iterar como mejor le parezca.
Así es como haría algo como esto en Kotlin con el SDK de Android.
Puede que no sea necesariamente en un viaje de ida y vuelta, pero agrupa eficazmente el resultado y evita muchas devoluciones de llamada anidadas.
val userIds = listOf("123", "456")
val userTasks = userIds.map { firestore.document("users/${it!!}").get() }
Tasks.whenAllSuccess<DocumentSnapshot>(userTasks).addOnSuccessListener { documentList ->
//Do what you need to with the document list
}
Tenga en cuenta que buscar documentos específicos es mucho mejor que buscar todos los documentos y filtrar el resultado. Esto se debe a que Firestore le cobra por el conjunto de resultados de la consulta.
Esto no parece ser posible en Firestore en este momento. No entiendo por qué se acepta la respuesta de Alexander, la solución que propone simplemente devuelve todos los documentos de la colección "usuarios".
Dependiendo de lo que deba hacer, debe buscar duplicar los datos relevantes que necesita mostrar y solo solicitar un documento completo cuando sea necesario.
Lo mejor que puede hacer es no usarlo Promise.all
como su cliente, luego debe esperar.all
las lecturas antes de continuar.
Repite las lecturas y deja que se resuelvan de forma independiente. En el lado del cliente, esto probablemente se reduce a que la interfaz de usuario tiene varias imágenes del cargador de progreso que se resuelven en valores de forma independiente. Sin embargo, esto es mejor que congelar a todo el cliente hasta.all
resuelvan las lecturas.
Por lo tanto, descargue todos los resultados síncronos en la vista inmediatamente, luego deje que los resultados asincrónicos entren a medida que se resuelven, individualmente. Esto puede parecer una distinción insignificante, pero si su cliente tiene una mala conectividad a Internet (como la que tengo actualmente en esta cafetería), congelar toda la experiencia del cliente durante varios segundos probablemente resultará en una experiencia de 'esta aplicación apesta'.
Promise.all
... no necesariamente tiene que "congelar" nada; es posible que deba esperar todos los datos antes de poder hacer algo significativo
Espero que esto te ayude, me funciona.
getCartGoodsData(id) {
const goodsIDs: string[] = [];
return new Promise((resolve) => {
this.fs.firestore.collection(`users/${id}/cart`).get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
goodsIDs.push(doc.id);
});
const getDocs = goodsIDs.map((id: string) => {
return this.fs.firestore.collection('goods').doc(id).get()
.then((docData) => {
return docData.data();
});
});
Promise.all(getDocs).then((goods: Goods[]) => {
resolve(goods);
});
});
});
}
a
,b
,c
hacer algo. Solicito los tres en paralelo en solicitudes separadas.a
tarda 100 ms,b
150 ms yc
3000 ms. Como resultado, necesito esperar 3000ms para realizar la tarea. Va a sermax
de ellos. Va a ser más arriesgado cuando la cantidad de documentos a buscar es grande. Depende del estado de la red, creo que esto puede convertirse en un problema.SELECT * FROM docs WHERE id IN (a,b,c)
embargo, ¿no tomaría la misma cantidad de tiempo enviarlos todos como uno solo ? No veo la diferencia, ya que la conexión se establece una vez y el resto se canaliza sobre eso. El tiempo (después del establecimiento inicial de la conexión) es el tiempo de carga de todos los documentos + 1 viaje de ida y vuelta, el mismo para ambos enfoques. Si se comporta diferente para usted, ¿puede compartir una muestra (como en mi pregunta vinculada)?