19
votes

When I delete a post in my Firebase database I want a cloud function to delete the post's thumbnail in firebase storage accordingly. My issue is when I'm trying to delete the thumbnail I don't think I'm locating the image file correctly.

Here is what I have tried:

const functions = require('firebase-functions')
const admin = require('firebase-admin')
const gcs = require('@google-cloud/storage')()

exports.deletePost = functions.database.ref('Posts/{pushId}').onWrite(event => {

  const original = event.data.val()
  const previous = event.data.previous.val()
  const pushId = event.params.pushId

  if (original === null)
    return

  const filePath = 'Posts/' + pushId + 'thumbnail.jpg'
  const bucket = gcs.bucket('postsapp-12312')
  const file = bucket.file(filePath)
  const pr = file.delete()


  return pr
});

This is what I'm getting in logs

ApiError: Not Found at Object.parseHttpRespBody (/user_code/node_modules/@google-cloud/storage/node_modules/@google-cloud/common/src/util.js:192:30) at Object.handleResp (/user_code/node_modules/@google-cloud/storage/node_modules/@google-cloud/common/src/util.js:132:18) at /user_code/node_modules/@google-cloud/storage/node_modules/@google-cloud/common/src/util.js:465:12 at Request.onResponse [as _callback] (/user_code/node_modules/@google-cloud/storage/node_modules/retry-request/index.js:120:7) at Request.self.callback (/user_code/node_modules/@google-cloud/storage/node_modules/request/request.js:188:22) at emitTwo (events.js:106:13) at Request.emit (events.js:191:7) at Request. (/user_code/node_modules/@google-cloud/storage/node_modules/request/request.js:1171:10) at emitOne (events.js:96:13) at Request.emit (events.js:188:7)

5
require call for gcs, for me only worked as: const gcs = require('@google-cloud/storage'); , thanks to: stackoverflow.com/a/41352560/2162226Gene Bo

5 Answers

15
votes

For anyone else still head-scratching, I was able to get mine deleted by excluding the bucket name (and hence selecting the default firebase bucket):

 const bucket = admin.storage().bucket();
 const path = "path/to/file.wav";
 return bucket.file(path).delete();
7
votes

I have managed to fix it. The Issue here was that I was writing my bucket address wrong; it should be something like postsapp-12312.appspot.com instead of postsapp-12312

Update For a better way to put your bucket address check @Robert answer

5
votes

You can use the firebase functions environment config to get the bucket name:

const bucket = gcs.bucket(functions.config().firebase.storageBucket)
4
votes

take a look at this functions I have used

const app = admin.initializeApp();

export const onDeleteItem = 
 functions.firestore.document('collectionItems/{collectionID}/items/{itemID}')
   .onDelete((snap, context) => {
     const { collectionID } = context.params;
     const { itemID } = context.params
     return deleteItemImage(collectionID, itemID)
     }
 )

async function deleteItemImage(collectionID: string, itemID: string) {
  const path = `images/${collectionID}/${itemID}`;
  const bucket = app.storage().bucket();
  return bucket.file(path).delete()
    .then(function () {
      console.log(`File deleted successfully in path: ${path}`)
    })
    .catch(function (error) {
      console.log(`File NOT deleted: ${path}`)
    })
}
3
votes

As far as I'm aware, it is not possible to delete firebase storage files from within cloud functions. You can listen to change events on a storage bucket, but you can't interact with it.

The way that I managed this was to remove the 'post' from the database using .set(null). This returns a promise which, when it resolves, you can use to make a delete call to firebase storage.

firebase.database().ref('Posts/{pushId}').set(null).then(() => {
  console.log('Post deleted from database')
  firebase.storage().ref(`Posts/${pushId}thumbnail-image.jpg`).delete().then(() => {
    console.log('Successfully deleted thumbnail');
  }).catch(err => {
    console.log(err);
  });
}).catch(err => {
  console.log(err);
});

Firebase storage won't allow you to recursively delete an entire bucket, so you need to delete each file one-by-one.