Reputation: 87
I'm trying to get the parent document of all subcollection queries I get so my database looks something like this
/production/id/position/id/positionhistory
I got all the documents of position history but I also need some data from position and production. I was hoping if there is a way to get the documents of the parents in a collectionGroup query. I'm also using firestore v9.
const getHistory = async () => {
setLoading(true);
try {
const userHisRef = query(
collectionGroup(db, "positionhistory"),
where("userid", "==", currentUser.uid)
);
const querySnapshot = await getDocs(userHisRef);
let arr = [];
querySnapshot.forEach((doc) => {
console.log(doc.id);
arr.push(doc.id);
});
setLoading(false);
} catch (err) {
console.log(err);
setLoading(false);
}
};
getHistory();
Upvotes: 6
Views: 5328
Reputation: 83048
As indicated by Pierre Janineh you need to use the parent
properties of the DocumentReference
and CollectionReference
classes.
Concretely, for each QueryDocumentSnapshot
(which "offers the same API surface as a DocumentSnapshot
") in the QuerySnapshot
you can do:
const querySnapshot = await getDocs(userHisRef);
let arr = [];
querySnapshot.forEach((doc) => {
const docRef = doc.ref;
const parentCollectionRef = docRef.parent; // CollectionReference
const immediateParentDocumentRef = parentCollectionRef.parent; // DocumentReference
const grandParentDocumentRef = immediateParentDocumentRef.parent.parent; // DocumentReference
// ...
});
So you can easily get the DocumentReference
s (and the id
s) of the parent and grandparent docs.
However, you want to get some of the data of these parent/grandparent documents ("I also need some data from position and production") and this is more complicated... because you actually need to query these documents based on their DocumentReference
s.
For that you could use Promise.all()
with one or more arrays of promises that you build in the loop (as rapidly shown below) but, depending on how much data from the parents you need, you could also denormalize your data and add to the children the desired data from their parents and grandparents docs.
To get the data of all the parent and grandparent docs, you can do as follows:
const querySnapshot = await getDocs(userHisRef);
let arr = [];
const parentsPromises = [];
const grandparentsPromises = [];
querySnapshot.forEach((doc) => {
const docRef = doc.ref;
const parentCollectionRef = docRef.parent; // CollectionReference
const immediateParentDocumentRef = parentCollectionRef.parent; // DocumentReference
const grandParentDocumentRef = immediateParentDocumentRef.parent.parent; // DocumentReference
parentsPromises.push(getDoc(immediateParentDocumentRef));
grandparentsPromises.push(getDoc(grandParentDocumentRef));
// ...
});
const arrayOfParentsDocumentSnapshots = await Promise.all(parentsPromises);
const arrayOfGrandparentsDocumentSnapshots = await Promise.all(grandParentDocumentRef);
You will get two arrays of DocumentSnapshot
s from which you can get the data. But you most probably need to link each of them with its corresponding child/grandchild doc...
Since, with Promise.all()
, the returned values will be in order of the Promises passed, you can use the index of the initial array (i.e. the order in which you loop over the querySnapshot
with forEach
) but it is a bit cumbersome...
In addition, note that if you have several docs in one of the positionhistory
subcollections, you will fecth several time the same parent and grandparent docs. You could maintain a list of the doc IDs that were already fetched but, again, this adds some complexity.
So, for all these reasons, it is probably good to analyse if it's not easier/better to denormalize the data, as explained above.
Upvotes: 14
Reputation: 702
You can use the QuerySnapshot
. It points to a number of QueryDocumentSnapshot
instances.
const parent = querySnapshot.ref.parent;
Check out the Firebase Documentation
Upvotes: 2