Currently, I am working on a pretty complicated set of queries to firestore.
I am trying, all at once, to populate an array full of references to other documents, and then read those documents and put the information in an array.
More specifically to this example, I have 4 references in one collection. I want to get those references, and then using those references, query 4 documents and populate an array with the information.
The order is as follows: do a query for all of the documents in the tags
subcollection, which is handled by the function below:
getTagsOnPage(workspaceId: string, pageId: string) {
// get all of the references in the tags sub-collection, and puts them in an array
// get all id's, do not get data
return this.afs
.collection("users")
.doc(`${auth().currentUser.uid}`)
.collection<Workspace>("workspaces")
.doc(`${workspaceId}`)
.collection<Page>("pages")
.doc(`${pageId}`)
.collection("tags")
.snapshotChanges()
.pipe(
map((actions) => {
return actions.map((a) => {
const ref = a.payload.doc.get("reference");
return ref; // return an array of (id: reference) key-value pairs
});
})
);
}
This works fine with the following code performing the subscription:
this.pageService
.getTagsOnPage(this.workspaceId, this.currentPage.id)
.subscribe((data) => {
temp = data;
});
data
is as follows, via the console:
(3) ["/users/ucB5cF4Pj3PWhRn10c9mvqQbS7x2/workspaces/It1…1tSnPI5GJrniY82vZL/localTags/1p5Tscwn14PyK6zRaFHX", "/users/ucB5cF4Pj3PWhRn10c9mvqQbS7x2/workspaces/It1tSnPI5GJrniY82vZL/localTags/lFKoB0jngmtnALut2QS2", "/users/ucB5cF4Pj3PWhRn10c9mvqQbS7x2/workspaces/It1tSnPI5GJrniY82vZL/localTags/r6sf2SX6v87arU2rKsD5"]
Now, to perform the next set of data reads is where my confusion begins.
My initial approach was to try a for loop (for the length of this array), but this would involve iterating performing a number of nested subscriptions, which I do not think is possible in this sense.
I am fairly new to rxjs, and have only used the map and switchMap operators. In this case, I am imagining I would use something like mergeMap
and/or flatMap,
but frankly, I am not sure how to make this work in this case. Also, dealing with the for loop where I need to grab documents based on the array of documentReferences I get is also throwing me for a loop.
This is my current implementation, which is all over the place; I hope the feel for what I am trying to do is there. Basically, get the array of references via getTagsOnPage, wait for the observable to end, use switchMap to take the data array and loop over it; ideally, subscribe to each ref and add to tagData, and then return that:
let tagData;
this.pageService.getTagsOnPage(this.workspaceId, this.currentPage.id).pipe(
switchMap((data) => {
let references = data;
for (let j = 0; j < references.length; j++) {
let ref = this.afs.doc(`${references[j]}`);
ref.snapshotChanges().pipe(
map((actions) => {
const data = actions.payload.data();
tagData.push(data);
})
);
// push the data (different data var)
}
})
);
return tagData;
Messy, I know, but I think once I know the right operators to use this will make a lot more sense.
Also, atm this returns an empty array. There is an error for when I use switchMap that says the following:
Argument of type '(data: any[]) => void' is not assignable to parameter of type '(value: any[], index: number) => ObservableInput<any>'.
Type 'void' is not assignable to type 'ObservableInput<any>'.
Thank you for any help!
combineLatest
could be an right operator for your case. What you can do ismap
getTagsOnPage
results tothis.afs.doc().snapshotChanges()
and pass it to that operator. – Buczkowski