In Firebase Firestore, I have a collection wherein each doc contains an id array a subcollection; like this:
collection: households
>>> doc: household1, members = [1]
>>> >>> collection entries
>>> >>> >>> entry 1, <data>
>>> >>> >>> entry 2, <data>
>>> doc: household2, members = [1, 2]
>>> >>> collection entries
>>> >>> >>> entry 3, <data>
>>> >>> >>> entry 4, <data>
>>> >>> >>> entry 5, <data>
I want to query all entries where user 1 is a member of. I want to do this with listeners so that my data updates when (1) the households change or when (2) the entries change.
How do I do this?
I've tried to query first the corresponsing households and afterwards get the corresponding entries, like this:
// Loop trough all households of user
db.collection("households")
.where("members", "array-contains", uid)
.where("status", "==", "active")
.onSnapshot((snapshotChange) => {
// Loop trough entry of each household
snapshotChange.forEach((householdsDoc) => {
db.collection("households")
.doc(householdsDoc.id)
.collection("entries")
.onSnapshot((snapshotChange) => {
snapshotChange.forEach((doc) => {
// Prepare entry
let currentDoc = doc.data();
currentDoc["id"] = doc.id;
// Handle change according to type
snapshotChange.docChanges().forEach((change) => {
console.log(change.type, "change.doc.id", change.doc.id);
if (change.type === "added") {
this.entries.push(currentDoc);
} else if (change.type === "modified") {
let index = this.entries.findIndex(
(el) => el.id === change.doc.id
);
if (index > -1) {
this.entries.splice(index, 1);
}
this.entries.push(currentDoc);
} else if (change.type === "removed") {
let index = this.entries.findIndex(
(el) => el.id === change.doc.id
);
if (index > -1) {
this.entries.splice(index, 1);
}
}
});
});
});
For this code, I get this from the console:
As you can see, somehow some ids arrive multiple times. Why is that?
Reads and listeners in Firestore are shallow. There is no way to perform a read/query on households and also get entries from the subcollections in one go.
You can either:
Neither of these is pertinently better than the other, so look at your specific use-case to see what results in the fewest reads/cost and best performance.