77 votes

Firestore récupère tous les docs et sous-collections de la collection Root

Disons que j'ai ce genre de structure

    A (collection): { 
       a (doc): {
           name:'Tim',
           B (collection):{
               b (doc): {
                      color:'blue'
               }
             }
          }
    }

A et B sont collections tandis que a et b sont documents .
Existe-t-il un moyen d'obtenir tout le contenu d'un document racine avec une seule requête ?
Si je fais une requête comme ceci

db.collection("A").doc("a").get()

Je viens de recevoir name:'Tim' champ. Ce que je veux, c'est obtenir également tous les documents de B.
Je souhaite essentiellement que ma requête renvoie

         {
           user:'Tim',
           B (collection):{
               b (doc): {
                      color:'blue'
               }
             }
          }

Est-ce possible ou dois-je vraiment faire plusieurs requêtes, une pour chaque collection :/ ?

Supposons que j'aie un arbre imbriqué très profond de collections représentant le profil de l'utilisateur, mes coûts vont augmenter considérablement, car chaque fois que je charge un profil d'utilisateur, je multiplie les demandes de lecture. 1 x N où N est la profondeur de mon arbre :/.

0 votes

Quel type est B ? Il existe un type de référence que vous pouvez essayer.

0 votes

Le type de référence aboutit au même problème, les données ne sont pas récupérées.

0 votes

Maintenant possible : firebase.googleblog.com/2019/06/

40voto

Matthew Rideout Points 998

Si vous vous préoccupez des coûts de chaque extraction, vous devrez structurer vos données en fonction de vos besoins communs en matière de vue et d'extraction, plutôt qu'en fonction d'une structure parfaite. Si vous avez besoin de tirer ces choses ensemble à chaque fois, Envisagez l'utilisation de "cartes". pour les choses qui n'ont pas réellement besoin d'être des sous-collections avec des documents.

Dans cet exemple, "préférences" est une carte.

{
  user: "Tim",
  preferences: {
      color: "blue",
      nickname: "Timster"
  }
}

La taille de chaque document est également limitée à 1 Mo. Par conséquent, si vous devez stocker quelque chose pour cet utilisateur qui va évoluer et continuer à croître, comme les enregistrements de journaux, il serait logique de répartir les journaux dans une sous-collection qui n'est extraite que lorsque vous le souhaitez, en faisant de chaque entrée de journal un document distinct... Et si tous les journaux pour tous les utilisateurs sont stockés dans une collection parente séparée, ou une sous-collection de chaque utilisateur, cela dépend vraiment de la façon dont vous tirerez les journaux et ce qui résultera en des vitesses rapides, équilibrées contre les coûts des tirages. Si vous voulez montrer à cet utilisateur ses 10 dernières recherches, il serait judicieux d'utiliser un journal de recherche comme sous-collection. Si vous extrayez toutes les données de recherche de tous les utilisateurs à des fins d'analyse, une collection distincte au niveau des parents serait judicieuse car vous pouvez extraire tous les journaux en une seule fois, ce qui évite d'avoir à extraire les journaux de chaque utilisateur séparément.

Vous pouvez également emboîter vos tirettes et vos promesses pour des raisons de commodité.

  // Get reference to all of the documents
  console.log("Retrieving list of documents in collection");
  let documents = collectionRef.limit(1).get()
    .then(snapshot => {
      snapshot.forEach(doc => {
        console.log("Parent Document ID: ", doc.id);

        let subCollectionDocs = collectionRef.doc(doc.id).collection("subCollection").get()
          .then(snapshot => {
            snapshot.forEach(doc => {
              console.log("Sub Document ID: ", doc.id);
            })
          }).catch(err => {
            console.log("Error getting sub-collection documents", err);
          })
      });
    }).catch(err => {
    console.log("Error getting documents", err);
  });

0 votes

Dans mon cas, le forEach extérieur se termine avant de traiter les éléments intérieurs, de sorte que ces derniers ne sont pas associés au bon document parent. Sortie : dropbox.com/s/2u831pue7edym2w/

0 votes

Cela dépend de ce que vous devez faire avec les données. L'objectif ici était de récupérer toutes les données. Si vous avez besoin qu'elles soient imprimées ou traitées de manière synchrone, vous devrez peut-être utiliser un compteur / une fonction récursive avec une fonction de rappel pour les traiter une par une. Gardez à l'esprit que cela augmentera considérablement vos coûts de lecture/écriture. Si vous n'avez besoin que de toutes les données, vous les avez toutes et vous pouvez en faire ce que vous voulez.

34voto

J Prakash Points 1105

Comme nous le savons, l'interrogation dans Cloud Firestore est superficielle par défaut. Ce type de requête n'est pas pris en charge, mais Google pourrait l'envisager à l'avenir.

14 votes

Maintenant supporté : firebase.googleblog.com/2019/06/

2 votes

@AshClarke J'ai parcouru l'article mais je n'ai pas compris comment le faire, pouvez-vous s'il vous plaît le poster comme une réponse et me mentionner également ? ou me guider dans la bonne direction ?

11 votes

@AshClarke, les requêtes collectionGroup interrogeront toutes les sous-collections d'un nom particulier à travers les documents, mais la requête est toujours peu profonde et ne renvoie pas l'arborescence entière du document. De plus, une fois que vous avez les résultats de la requête, il n'existe aucune méthode pour obtenir le document "propriétaire" (par défaut). Vous pouvez stocker le docID parent dans le document de la sous-collection et utiliser cette valeur pour récupérer le document parent, mais ce n'est pas automatique.

11voto

Or Duan Points 5708

En complément de la réponse de Matt R, si vous utilisez babel ou si vous pouvez utiliser async/await, vous pouvez obtenir le même résultat avec moins de code (pas de catch / then ) :

// Get reference to all of the documents
console.log("Retrieving list of documents in collection");
let documents = await collectionRef.get();

documents.forEach(async doc => {
  console.log("Parent Document ID: ", doc.id);
  let subCollectionDocs = await collectionRef.doc(doc.id).collection("subCollection").get()
  subCollectionDocs.forEach(subCollectionDoc => {
    subCollectionDoc.forEach(doc => {
      console.log("Sub Document ID: ", doc.id);
    })
});

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