Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/32.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular 什么';从Firestore文档中嵌套的集合中获取数据的最佳方法是什么?_Angular_Typescript_Firebase_Angularfire2_Google Cloud Firestore - Fatal编程技术网

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

Angular 什么';从Firestore文档中嵌套的集合中获取数据的最佳方法是什么?,angular,typescript,firebase,angularfire2,google-cloud-firestore,Angular,Typescript,Firebase,Angularfire2,Google Cloud Firestore,我正在浏览Firestore文档和指南。下面的代码示例使用AngularFire2 让我们考虑一个类似于这里提供的例子的“聊天”集合: 他们推荐这种结构,但我看不出他们在哪里讨论如何有效地获取所有数据 每个聊天文档都有属性、成员集合和消息集合: chatsCollection 聊天记录 [在此插入聊天数据字段] 成员集合 成员文件 [在此插入成员数据字段] 信息收集 消息文档 [在此插入消息数据字段] Firestore查询很浅,有时可能很好。我的理解是,没有现成的方

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

让我们考虑一个类似于这里提供的例子的“聊天”集合:

他们推荐这种结构,但我看不出他们在哪里讨论如何有效地获取所有数据

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

  • chatsCollection
    • 聊天记录
      • [在此插入聊天数据字段]
      • 成员集合
        • 成员文件
          • [在此插入成员数据字段]
      • 信息收集
        • 消息文档
          • [在此插入消息数据字段]
Firestore查询很浅,有时可能很好。我的理解是,没有现成的方法来查询deep和获取嵌套集合。那么,做这件事的最佳实践和最省事的方法是什么呢

目前,我正在使用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');
}
getChatsFromFirestore(){
返回此.fsd.集合(“聊天”);
}
getChatFromFirestoreById(id:string){
返回这个.fsd.doc(`chats/${id}`);
}
getMembersForChat(聊天ID){
返回此.getChatFromFirestoreById(chatId).collection('members');
}

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

通过使用助手函数
observeCollection
以及小代码重组,它将清理服务并为每个聊天室创建在订阅之前处于非活动状态的观察对象

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;
        });
    }
}
在应用程序中,您只能观察当前选定的聊天室成员和消息,这将保存数据。 因为这篇文章是用角度异步管道标记的,所以自动手动订阅将有助于切换

在您的组件中:

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>

{{currentChat.name}
{{member.name}
{{message.content}

我想这里有一个论点是按照实时数据库的流程复制和反规范化数据(类似),但我也希望有一个不同的/更好的流程来连接Firestore中的数据。这一点很好,在这种情况下,我做了一些复制和反规范化数据的工作。例如,每个聊天室都包含其成员,其文档ID与UID匹配,UID可用于获取该成员的所有数据,但也包含用户名。每个单独的消息还包含一个“authorName”字段和一个“sentBy”字段,该字段再次保存该用户的UID。。。尽管如此,能够在聊天室文档下获取所有嵌套数据而无需对数据库进行递归调用,或者至少使用更少的详细代码将是很酷的。如果将id与
聊天室文档
一起保存为字段,则可以使用
.valueChanges()
获取id。这比
快照更改()更快
。如何仅为用户获取相关的聊天室文档?每个用户都能看到每个聊天吗?这只是Firebase文档中数据的一个相关示例。为用户获取相关的聊天文档将遵循稍微不同的路径,但仍然需要嵌套的、连续的数据库查询。在其他情况下,我可能希望一次获得一个文档列表及其所有嵌套数据,就像在示例中一样。如果答案指向正确的方向,欢迎进一步讨论。