I have Firestore database with documents structure like this
startDate - String
endDate - String
pages - Array(String)
and Storage database with files by following path:
/pages/fileID
I run cron job with Firebase Functions to remove stale data. And when I remove records from Firestore I want to remove associated with this record files from Storage also, but get the error: No such object (from Google Cloud console logs). How to do that correctly?
const functions = require("firebase-functions")
const admin = require("firebase-admin")
admin.initializeApp({ storageBucket: "..." })
var firestore = admin.firestore()
exports.deleteEntries = functions.pubsub.schedule("* * * * *")
.onRun(async () => {
const bucket = admin.storage().bucket()
const timeElapsed = Date.now()
const today = new Date(timeElapsed)
const albumsRef = firestore.collection('albums')
const albums = await albumsRef.where('endDate', '<', today.toISOString()).get()
albums.forEach(async snapshot => {
snapshot.ref.delete() // This works fine, file removed from Firestore - success
const promises = []
await snapshot.ref.get().then(doc => {
doc.data().pages.forEach(path => { // Error: No such object
promises.push(bucket.file(`/${path}`).delete())
})
})
await Promise.all(promises)
})
return null
})
Mixing forEach
and async/await
is not recommended, see "JavaScript: async/await with forEach()" and "Using async/await with a forEach loop".
The following code should do the trick (untested):
exports.deleteEntries = functions.pubsub
.schedule("* * * * *")
.onRun(async () => {
const bucket = admin.storage().bucket();
const timeElapsed = Date.now();
const today = new Date(timeElapsed);
const albumsRef = firestore.collection("albums");
const albums = await albumsRef
.where("endDate", "<", today.toISOString())
.get();
const promises = [];
albums.forEach((albumSnapshot) => {
promises.push(albumSnapshot.ref.delete());
albumSnapshot.data().pages.forEach((path) => {
promises.push(bucket.file(`/${path}`).delete());
});
});
await Promise.all(promises);
return null;
});
Explanations:
albumSnapshot.ref.delete()
is an asynchronous operation, so you should add it to the promises Array as wellawait snapshot.ref.get().then()
since the snapshot already contains the document's data. In addition mixing async/await
and then()
is not recommended neither (even if it works).