Reputation: 85
I have 2 collections in my firestore. One called owners and the second is unicorns. An owner has only a name field and a unicorn has a name and a reference to the owner. I want a query to return an array of objects that looks like this
unicorns = { id: 123,
name: Dreamy,
owner: { id: 1
name: John Cane
}
}
my query looks like this but there is something missing that I can't figure out
let unis = [];
db
.collection("unicorns")
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
let uni = {
id: doc.id,
name: doc.data().name,
owner: doc.data().owner,
};
if (uni.owner) {
doc
.data()
.owner.get()
.then((res) => {
uni.owner = {
id: res.id,
name: res.data().name,
};
unis.push(uni);
})
.then(() => {
setUnicorns(unis);
})
.catch((err) => console.error(err));
} else {
unis.push(uni);
}
});
})
When I setUnicorns hook and I try to map the results I don't get all the data I need
Upvotes: 2
Views: 3082
Reputation: 50900
You cannot run the .get()
method on a string. You would have to run a separate request to firestore to get owner documents. I would recommend using a for-of inside a async function as shown below.
const db = admin.firestore()
//Declare the reference for collections before the loop starts
const ownersCollection = db.collection("owners")
const unicornsCollection = db.collection("unicorns")
const ownersData = {}
let unis = [];
unicornsCollection.get().then(async (querySnapshot) => {
for (const doc of querySnapshot) {
let uni = {
id: doc.id,
name: doc.data().name,
//Assuming the owner field is the UID of owner
owner: doc.data().owner,
};
if (uni.owner) {
//Check if owner's data is already fetched to save extra requests to Firestore
if (ownersData[uni.owner]) {
uni.owner = {
id: ownersData[uni.owner].id,
name: ownersData[uni.owner].name,
};
unis.push(uni);
} else {
//User the ownersCollection Reference to get owner information
ownersCollection.doc(uni.owner).get().then((ownerDoc) => {
uni.owner = {
id: ownerDoc.data().id,
name: ownerDoc.data().name,
};
ownersData[uni.owner] = {
id: ownerDoc.data().id,
name: ownerDoc.data().name,
}
unis.push(uni);
}).then(() => {
setUnicorns(unis);
}).catch((err) => console.error(err));
}
} else {
unis.push(uni);
}
}
})
How this works? It fetches all the unicorn documents and iterates over then to check if the document has owner's UID. If yes then runs another request to Firestore to get that unicorn's owner's document. Let me know if you have any questions.
Edit: In case a single owner has multiple unicorns then you surely don't want to fetch the data of same owner again and again. So add that in an object locally and check if the data of that owner is already fetched before making a request to Firestore. Code for the same updated above.
Upvotes: 1