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

问题描述 投票:9回答:1

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

让我们考虑一个类似于这里提供的例子的“聊天”集合: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');
}
angular typescript firebase angularfire2 google-cloud-firestore
1个回答
0
投票

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

通过使用辅助函数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>
© www.soinside.com 2019 - 2024. All rights reserved.