首页 文章

从嵌套在Firestore中的文档中的集合中获取数据的最佳方法是什么?

提问于
浏览
9

我正在浏览Firestore文档和指南 . 我下面的代码示例使用AngularFire2 .

让我们考虑一个类似于此处提供的示例的"chats"集合:https://firebase.google.com/docs/firestore/manage-data/structure-data

他们推荐这种结构,但我不知道他们在哪里讨论有效地获取所有数据 .

每个聊天文档都有属性,成员集合和消息集合:

  • chatsCollection

  • chatDocument

  • [此处插入聊天数据字段]

  • membersCollection

  • memberDocument

  • [在此处插入会员数据字段]

  • messagesCollection

  • messageDocument

  • [在此处插入消息数据字段]

Firestore查询很浅,有时可能很棒 . 我的理解是,没有编入方式来深入查询并获取嵌套集合 . 那么,最好的做法和最无忧无虑的方法是什么?

目前我正在检索快照并将快照映射到具有ID的对象,并将嵌套的集合数据添加到父文档数据中,并附加查询和映射,我对我的方法感到不满意,即使使用非规范化的Firebase也可以更快地完成结构 .

这个代码示例只是在成员上映射,在消息中添加回来是另一个故事......

getChatsFromFirestore() {
    this.chats = this.dataSvc.getChatsFromFirestore().snapshotChanges()
      .map(chatSnaps => {
        return chatSnaps.map(chat => {
          const chatData = chat.payload.doc.data();
          const chatId = chat.payload.doc.id;
          return this.dataSvc.getMembersForChat(chatId)
            .snapshotChanges()
            .map(memberSnaps => {
              return memberSnaps.map(member => {
                const data = member.payload.doc.data();
                const id = member.payload.doc.id;
                return { id, ...data }
              });
            })
            .map(members => {
              return { chatId, ...chatData, members: members };
            });
        })
      })
      .flatMap(chats => Observable.combineLatest(chats));
  }

从服务:

getChatsFromFirestore() {
  return this.fsd.collection<any>('chats');
}
getChatFromFirestoreById(id: string) {
  return this.fsd.doc(`chats/${id}`);
}
getMembersForChat(chatId) {
  return this.getChatFromFirestoreById(chatId).collection('members');
}

1 回答

  • 0

    您发布的方法似乎可行,对于大型聊天应用程序,您可能不希望跟踪每个聊天室中发生的每个事件,因为这可能是大量数据 . 相反,最好只订阅所需内容并使用 Cloud 功能和 Cloud 消息处理定期更新 .

    通过使用帮助函数 observeCollection 以及小代码重构,它将清理服务并为每个聊天室创建observable,这些聊天室在订阅之前将处于非活动状态 .

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

    在应用程序中,您只能观察当前选定的聊天室成员和消息,这将保存数据 . 由于此帖子标有Angular异步管道,因此可以通过自动手动下标来帮助切换 .

    在您的组件中:

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

    在您的模板中:

    <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>
    

相关问题