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: https://firebase.google.com/docs/firestore/manage-data/structure-data
They recommend this kind of structure but I don't see where they discuss getting all the data efficiently.
Each chat document has properties, a collection of members, and a collection of messages:
- chatsCollection
- chatDocument
- [insert chat data fields here]
- membersCollection
- memberDocument
- [insert member data fields here]
- memberDocument
- messagesCollection
- messageDocument
- [insert message data fields here]
- messageDocument
- chatDocument
Firestore queries are shallow, which could be great sometimes. My understanding is that there's no baked-in way to query deep and get nested collections. So, what are the best practices and most hassle-free ways to do this?
At the moment I'm retrieving and mapping snapshots to objects with IDs and adding the nested collection data onto the parent document data with additional queries and mappings, and I'm not happy with my approach, and could do it quicker even with denormalized Firebase structures.
This code example is just mapping on the members, adding back in messages is a whole other story...
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));
}
And from the service:
getChatsFromFirestore() {
return this.fsd.collection<any>('chats');
}
getChatFromFirestoreById(id: string) {
return this.fsd.doc(`chats/${id}`);
}
getMembersForChat(chatId) {
return this.getChatFromFirestoreById(chatId).collection('members');
}