Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firestore get all docs and subcollections of root collection

Say I have this kind of structure

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

where A and B are collections while a and b are documents.
Is there a way to get everything contained in a root document with one query?
If I query like this

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

I just gets name:'Tim' field. What I want is to also get all B's documents.
I basically wish my query returns

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

Is it possibly or do I really need to make multiple queries one for each collection :/ ?

Say I have a really deep nested tree of collections representing the user profile, my costs will raise like hell since each time I load a user profile I have a multiplier of read requests 1 x N where N is the depth of my tree :/.

like image 633
r4id4 Avatar asked Oct 22 '17 15:10

r4id4


People also ask

How do I find out how many documents are in my firestore collection?

If you need a count, just use the collection path and prefix it with counters . As this approach uses a single database and document, it is limited to the Firestore constraint of 1 Update per Second for each counter.

How do I get all the collection names in firestore?

js admin clients have listCollections() on Firestore to get that list. Or, if you're looking for subcollections nested under a document, use DocumentReference. listCollections(). If you want to get a list on any platform, you should maintain that list yourself in a known collection inside a known document id.


3 Answers

If you are concerned about costs of each pull, you will need to structure your data according to your common view / pull needs, rather than what you might prefer for a perfect structure. If you need to pull these things together every time, Consider using "maps" for things that do not actually need to be sub-collections with documents.

In this example, "preferences" is a map.

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

Each document is also limited in size to 1MB - so if you need to store something for this user that will scale and continue to grow, like log records, then it would make sense to break logs into a sub-collection that only gets pulled when you want it, making each log entry a separate document... And whether all logs for all users are stored in a separate parent collection, or a sub-collection of each user really depends on how you will be pulling logs and what will result in fast speeds, balanced against costs of pulls. If you're showing this user their last 10 searches, then a search-log would make good sense as a sub-collection. If you're pulling all search data for all users for analysis, then a separate parent level collection would make sense because you can pull all logs in 1 pull, to prevent the need to pull logs from each user separately.

You can also nest your pulls and promises together for convenience purposes.

  // 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);
  });
like image 125
Matthew Rideout Avatar answered Oct 06 '22 19:10

Matthew Rideout


As we know querying in Cloud Firestore is shallow by default. This type of query isn't supported, although it is something Google may consider in the future.

like image 35
J Prakash Avatar answered Oct 06 '22 18:10

J Prakash


Adding to Matt R answer, if you're using babel or you can use async/await, you can get the same result with less code(no 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);
        })
    });
});
like image 10
Or Duan Avatar answered Oct 06 '22 20:10

Or Duan