I posted this on StackOverflow originally, but would welcome any suggestions:
Scenario
My app is built with React and Firebase. There is a feature in the app that allows users to create playlists and fill them with tracks from a catalog. A Playlist has a sub-collection called "Tracks" that stores the track ID's and some other info. When viewing a playlist, I want to loop through the tracks and cross-reference them (like a join in SQL) to the Tracks collection to populate the view.
// Looks something like this before the return...
// Attempting to write an async/await function
async function getTrackDocument(trackId) {
const track = await firestore
.collection("tracks")
.doc(trackId)
.get();
return track;
}
useEffect(() => {
const playlistRef = firestore.doc(`playlists/${playlistId}`);
const playlistTracksRef = firestore.collection(
`playlists/${playlistId}/tracks`
);
playlistRef.get().then(doc => {
if (doc.exists) {
const unsubscribe = playlistTracksRef.onSnapshot(snapshot => {
// Snapshot of playlist tracks
const playlistTracks = snapshot.docs.map(doc => {
return {
id: doc.id,
...doc.data(),
// Getting the track document
trackRef: getTrackDocument(doc.id).then(doc => {
return doc.data();
})
};
});
setTracks(playlistTracks);
});
return () => unsubscribe();
}
});
});
Problem
The part where I am trying to cross-reference a Playlist Track ID to the Tracks collection:
trackRef: getTrackDocument(doc.id).then(doc => {
return doc.data();
})
I was hoping that would give me the track information I needed. That part returns a promise object in the console:
trackRef: Promise
__proto__: Promise
[[PromiseStatus]]: "resolved"
[[PromiseValue]]: Object
__proto__: Object
And [[PromiseValue]]
has all the values, but I can't get seem to get to where I can use the values. I can log doc.data()
to the console and it shows me the values I need eventually. Is there a way to return those values in-line the way the code is written? I've tried different ways of writing async/await functions, and I also tried to return a Promise.resolve(data), always the same results.
The closest I've come to the behavior I was hoping for was by creating a function where I could grab the Track and just push it to tracks array in state, like:
// @param arrayOfTrackIDs -- just track IDs from the playlist
function getTracksThenPopulateArray(arrayOfTrackIDs) {
arrayOfTrackIDs.forEach(trackID => {
firestoreTracks.doc(trackID).get().then(doc => setTracks(tracks => [...tracks, track]));
}
}
This wasn't ideal however because I couldn't incorporate .onSnapshot() to update the view if tracks were removed or added.
Top comments (1)
I followed this tut and got to this comment :)
https://www.youtube.com/watch?v=2qkAfddVbKM&t=708s
Document Reference does not equal id