What's the best way to get data from collections nested in documents in Firestore?

后端 未结 1 1777
灰色年华
灰色年华 2021-02-03 10:45

I\'m going through the Firestore docs and guide. My code samples below use AngularFire2.

Let\'s consider a \"chats\" collection similar to the examples provided here: ht

相关标签:
1条回答
  • 2021-02-03 11:23

    The approach you posted seems like it would work and for a large chat application you probably do not want to track every single event that happens in every chatroom as that could be a lot of data. Instead it would probably be better to subscribe to only what is needed and handle periodic updates with cloud functions and cloud messaging.

    By using a helper function observeCollection as well as small code restructuring it would cleanup the service and create observables for each chatroom that would be inactive until they are subscribed to.

    class Service {
        // db is plan firestore / no angularfire
        db: firebase.firestore.Firestore;
    
        loadChatrooms() {
            const chatsRef = this.db.collection('chats');
            return observeCollection(chatsRef)
                .pipe(
                    map(chats => {
                        return chats.map(chat => {
                            return {
                                chat,
                                members$: this.observeCollection(chat.ref.collection('members')),
                                messages$: this.observeCollection(chat.ref.collection('messages')),
                            };
                        })
                    }),
                );
        }
    
        // Takes a reference and returns an array of documents
        // with the id and reference
        private observeCollection(ref) {
            return Observable.create((observer) => {
                const unsubscribeFn = ref.onSnapshot(
                    snapshot => {
                        observer.next(snapshot.docs.map(doc => {
                            const data = doc.data();
                            return { 
                                ...doc.data(),
                                id: doc.id,
                                ref: doc.ref
                            };
                        }));
                    },
                    error => observer.error(error),
                );
    
                return unsubscribeFn;
            });
        }
    }
    

    In the application you could then only observe the currently selected chatrooms members and messages, which would save data. Since this post is tagged with Angular async pipes would help with switching by automatically handly subscriptisons.

    In your component:

    this.currentChat$ = combineLatest(
      service.loadChatrooms(),
      currentlySelectedRoomId
    ).pipe(
        map(([chats, selectedRoomId]) => {
            return chats.first(chat => chat.id === selectedRoomId)
        })
    );
    

    In your template:

    <div *ngIf="currentChat$ as currentChat">
        {{ currentChat.name }}
    
        <div *ngIf="currentChat.members$ as members">
            <div *ngIf="let member of members">
              {{ member.name }}
            </div> 
        </div> 
    
        <div *ngIf="currentChat.messages$ as messages">
            <div *ngIf="let message of messages">
              {{ message.content }}
            </div> 
        </div> 
    </div>
    
    0 讨论(0)
提交回复
热议问题