192 votes

Google Firestore - Comment obtenir plusieurs documents par plusieurs identifiants en un seul aller-retour ?

Je me demande s'il est possible d'obtenir plusieurs documents par une liste d'identifiants en un seul aller-retour (appel réseau) vers la base de données Firestore.

5 votes

Vous semblez supposer que les allers-retours causent des problèmes de performance dans votre application. Je ne le penserais pas. Firebase a l'habitude de fonctionner correctement dans de tels cas, puisqu'il canaliser les demandes . Je n'ai pas vérifié comment Firestore se comporte dans ce scénario, mais j'aimerais bien avoir la preuve d'un problème de performance avant de supposer qu'il existe.

4 votes

Disons que j'ai besoin de documents a , b , c pour faire quelque chose. Je demande les trois en parallèle dans des demandes séparées. a prend 100 ms, b prend 150ms, et c prend 3000ms. Par conséquent, je dois attendre 3000ms pour effectuer la tâche. Cela va être max d'entre eux. Cela va être plus risqué lorsque le nombre de documents à récupérer est important. Selon l'état du réseau, je pense que cela peut devenir un problème.

1 votes

Ne les enverrait-on pas tous en une seule fois ? SELECT * FROM docs WHERE id IN (a,b,c) prennent le même temps pourtant ? Je ne vois pas la différence, puisque la connexion est établie une seule fois et que le reste est acheminé en pipeline par-dessus. Le temps (après l'établissement initial de la connexion) est le temps de chargement de tous les documents + 1 aller-retour, identique pour les deux approches. Si le comportement est différent pour vous, pouvez-vous partager un échantillon (comme dans ma question liée) ?

160voto

Nick Franceschina Points 1794

Si vous êtes dans Node :

https://github.com/googleapis/nodejs-firestore/blob/master/dev/src/index.ts#L978

/**
* 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])}`);
* });
*/

Ceci est spécifiquement pour le SDK du serveur

UPDATE : "Cloud Firestore [sdk côté client] supporte désormais les requêtes IN !"

https://firebase.googleblog.com/2019/11/cloud-firestore-now-supports-in-queries.html

myCollection.where(firestore.FieldPath.documentId(), 'in', ["123","456","789"])

37 votes

Si vous souhaitez appeler cette méthode avec un tableau de références de documents généré dynamiquement, vous pouvez procéder comme suit : firestore.getAll(...arrayOfReferences).then()

0 votes

@NickFranceschina savez-vous comment cela peut être utilisé sur angularfire ou firebase vanilla libs ?

1 votes

Je suis désolé @KamanaKisinga ... Je n'ai pas fait de travaux sur Firebase depuis presque un an et je ne peux pas vraiment aider en ce moment (regardez, j'ai posté cette réponse il y a un an aujourd'hui !)

55voto

Sebastian Points 82

En pratique, vous utiliserez firestore.getAll comme ceci

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()))
}

ou avec la syntaxe des promesses

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())))
}

18 votes

Cette réponse devrait vraiment être la réponse choisie car elle vous permet d'utiliser plus de 10 identifiants.

1 votes

Ça a marché ! Merci. Où se trouve la documentation à ce sujet ? J'ai cherché getAll et je ne l'ai trouvé nulle part.

7 votes

@TravRob cela peut être disponible dans certaines versions de Firebase, comme Node, mais ce n'est certainement pas dans l'API JavaScript.

12voto

JP de la Torre Points 84

Vous pourriez utiliser une fonction comme celle-ci :

function getById (path, ids) {
  return firestore.getAll(
    [].concat(ids).map(id => firestore.doc(`${path}/${id}`))
  )
}

Il peut être appelé avec un seul identifiant :

getById('collection', 'some_id')

ou un tableau d'identifiants :

getById('collection', ['some_id', 'some_other_id'])

11voto

hatboysam Points 1191

Non, pour l'instant, il n'existe aucun moyen de regrouper plusieurs demandes de lecture à l'aide du SDK Cloud Firestore et donc aucun moyen de garantir que vous pourrez lire toutes les données en une seule fois.

Cependant, comme l'a dit Frank van Puffelen dans les commentaires ci-dessus, cela ne signifie pas que la récupération de 3 documents sera 3x plus lente que la récupération d'un seul document. Il est préférable d'effectuer vos propres mesures avant de tirer une conclusion.

2 votes

Le problème est que je veux connaître les limites théoriques des performances de Firestore avant de migrer vers Firestore. Je ne veux pas migrer et me rendre compte ensuite que ce n'est pas suffisant pour mon cas d'utilisation.

0 votes

Pour moi, l'absence de prise en charge du batching n'est pas une bonne chose. La plupart des appels à la base de données de mon application consistent à récupérer plusieurs (souvent des centaines) de documents avec plusieurs identifiants. Pour être performants, ces appels doivent être mis en lot pour moi.

0 votes

@Joon il semble que vous devrez réévaluer vos structures de données pour être plus performant dans une base de données NoSQL comme Cloud Firestore. Le meilleur conseil que je puisse donner est de réfléchir à rebours à partir des requêtes. Pensez à une requête que vous aimeriez exécuter, et structurez vos données de manière à pouvoir l'exprimer simplement. Toutes les requêtes dans Cloud Firestore sont rapides.

5voto

Chris Wilson Points 51

Le meilleur moyen d'y parvenir est certainement d'implémenter la requête réelle de Firestore dans une fonction Cloud ? Il n'y aurait alors qu'un seul appel aller-retour du client à Firebase, ce qui semble être ce que vous demandez.

De toute façon, il est préférable de garder toute la logique d'accès aux données côté serveur.

En interne, il y aura probablement le même nombre d'appels à Firebase lui-même, mais ils passeront tous par les interconnexions ultra-rapides de Google, plutôt que par le réseau externe. Combiné au pipelining expliqué par Frank van Puffelen, vous devriez obtenir d'excellentes performances avec cette approche.

4 votes

Le stockage de l'implémentation dans une fonction Cloud est la bonne décision dans certains cas où vous avez une logique complexe, mais probablement pas dans le cas où vous voulez simplement fusionner une liste avec plusieurs identifiants. Ce que vous perdez, c'est la mise en cache côté client et le formatage de retour standardisé des appels réguliers. Cela a causé plus de problèmes de performance qu'il n'en a résolu dans certains cas dans mes applications lorsque j'ai utilisé cette approche.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X