简体   繁体   中英

Query through all documents in a collection, and through all subcollections in firestore

I am building an app using Firebase Firestore as a BaaS.

But I am facing a problem when I try to create a feed/implement full-text-search on my app.

I want to be able to search through all the users posts, the problem is, the users posts are structured like this in the Firestore Database:

Posts(collection) -> UserID(Document) -> user posts(subcollection that holds all userID posts) -> actual posts(separate doccuments within that collection)

I want to loop through every user's user posts subcollection and fetch all data for the feed, and also to implement it with a full text search app like Algolia or ES.

  • I can loop through a specific user ID(code below), but being a beginner, I couldn't find a way to loop through all of them and fetch all of them.

     firebase.firestore() .collection('allPosts') .doc('SPECIFIC_USER_ID') //-> Here I have to loop through all docs in that collection .collection('userPosts') .orderBy("creation", "asc") .get() .then((snapshot) => { let posts = snapshot.docs.map(doc => { const data = doc.data(); const id = doc.id; return { id, ...data } }) setUserPosts(posts) }) }

Would love some help!

Collection Group Query

You can query in all collections named X using a collection group query.

var posts= db.collectionGroup('userPosts').orderBy('creation').limit(10);
posts.get().then((querySnapshot) => {
              let posts = querySnapshot.map(doc => {
                  const data = doc.data();
                  const id = doc.id;
                  return { id, ...data }
              })
              setUserPosts(posts)
});

Source: https://firebase.google.com/docs/firestore/query-data/queries#collection-group-query

Algolia implementation

You will need to use Cloud Functions to migrate fields to a dedicated collection specifically for Algolia. Many users have found nested SubCollections to be problematic with Algolia's setup. You do this by duplicating the user Post data as a 'source' to this new public collection, and using the Firebase Algolia Extension, you can sync it directly

exports.bakePosts= functions.firestore
    .document('allPosts/{userID}/userPosts/{postID}')
    .onWrite((change, context) => {
      // Get an object with the current document value.
      // If the document does not exist, it has been deleted.
      const document = change.after.exists ? change.after.data() : null;

      // Get an object with the previous document value (for update or delete)
      const oldDocument = change.before.data();
      if(document != null)
          db.collection("posts/"+ context.params.postID).set(document);
      if(document == null)
          db.collection("posts/"+ context.params.postID).delete();
    });

Algolia Extension: https://firebase.google.com/products/extensions/firestore-algolia-search

You can avoid most of the above if you simply submit posts to a master collection and have the userID as the 'owner' property within the document. The above also have benefits, but more related to blog posts where users may have a "work in progress" version vs Live.

The Algolia Extension has the full guide on how to set it up and if you need to customize the extensions, the source code is also available.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM