6
votes

I have a collection of profiles in my Firestore db and a field named "profilePicture" with a downloadUrl as the value.

Im using cloud functions and been trying for a long time to figure out how to delete the profilePicture when the profile is deleted.

I know how to create a trigger when the profile is deleted and get the profile picture downloadUrl, but how do I delete the file from storage with only the downloadUrl?

6
How did you generate the download URL?Doug Stevenson
@DougStevenson I just retrieved it from the meta data when storing the picture on the device using swift.user3116871

6 Answers

12
votes

The firebase storage documentation provides a method refFromURL(url) that can be used on a Storage instance. It states the url argument can be:

A URL in the form:

1) a gs:// URL, for example gs://bucket/files/image.png

2) a download URL taken from object metadata.

Based (2) above, it seems like an HTTP URL should also work. However it probably is better practise to store a path string, as the tokens on the HTTP URLs can get rotated by Firebase.

7
votes

for admin.storage.Storage is no build in method for get reference from url for storage

but you can extract file path from URL ,by remove baseUrl and do some code replace on URL

im create method for this task to accept url from storage project and return path

function getPathStorageFromUrl(url:String){

    const baseUrl = "https://firebasestorage.googleapis.com/v0/b/project-80505.appspot.com/o/";

    let imagePath:string = url.replace(baseUrl,"");

    const indexOfEndPath = imagePath.indexOf("?");

    imagePath = imagePath.substring(0,indexOfEndPath);
    
     imagePath = imagePath.replace("%2F","/");
    
 
    return imagePath;
}

NOTE : You must replace baseUrl for every project, you can find it by open any image in you storage , and copy it from URL in browser from start to end of last slash '/'

Ex :

Some image link on my storage : 
https://firebasestorage.googleapis.com/v0/b/project-80505.appspot.com/o/RequestsScreenshot%2F-M6CA-2bG2aP_WwOF-dR__1i5056O335?alt=media&token=d000fab7

the base URL will be 
https://firebasestorage.googleapis.com/v0/b/project-80505.appspot.com/o/ 

now after get path call file to delete it from storage

const storage = admin.storage();

const imagePath:string = getPathStorageFromUrl(obj.imageUrl);

storage.bucket().file(imagePath).delete().catch((err) => console.error(err));

NOTE : There is no documentation explaining the format of the URL, which implies that the Firebase team might feel the need to change it some day , mean maybe will not work in the future if format is change.

6
votes

My understanding is that the node SDK for Cloud Storage can't convert HTTP URLs into file paths within a storage bucket. Instead, you should be storing the file path along with the download URL in document. This will make it possible for to build a File object that can be used to delete the image when it's time to do so.

5
votes

In Angular I use this to delete file from Cloud Firestore by downloadURL

constructor(private storage: AngularFireStorage) {}

onDeleteAttachment(downloadURL: string) {
  this.storage.storage.refFromURL(downloadURL).delete();
}
2
votes

confing.js

import firebase from 'firebase/app'
import "firebase/firestore";
import "firebase/storage";

const firebaseConfig = {
            apiKey: "XXXX",
            authDomain: "XXXXX.firebaseapp.com",
            databaseURL: "https://XXXX-app-web.firebaseio.com",
            projectId: "XXXX",
            storageBucket: "XXXX-app-web.appspot.com",
            messagingSenderId: "XXXXXX",
            appId: "1:XXX:web:XXXX",
            measurementId: "G-XXXX"
};
firebase.initializeApp(firebaseConfig);
export const firestore = firebase.firestore();
export const storageRef = firebase.storage();

export default firebase;

Button.js

import React from 'react';
import {firestore,storageRef} from './Config';

function removeFile(id,downloadUrl) {
  const storageRefa = storageRef.refFromURL(downloadUrl);

  storageRefa.delete().then(() => {
    firestore.collection("All_Files").doc(id).delete().then((response) => {
      console.log('delete response', response)
    }).catch((error) => {
      console.log('delete error', error)
    })
  }).catch((error) => {
    console.log('delete error', error)
  });
}
export default function MediaCard(props) {
  return (
    <>
           <Button
              onClick={() =>{
                removeFile(props.ID,props.downloadUrl)
              }}
              variant="contained"
              color="secondary"
          >
            Delete
          </Button>
    </>
  );
}
0
votes

Mahmoud's answer need a little edit .. it works tho .. He is doing the replacements wrongly and might not work if you have nested directories or spaced filenames in your storage

getPathStorageFromUrl(url:String){

        const baseUrl = "https://firebasestorage.googleapis.com/v0/b/project-80505.appspot.com/o/";
    
        let imagePath:string = url.replace(baseUrl,"");
    
        const indexOfEndPath = imagePath.indexOf("?");
    
        imagePath = imagePath.substring(0,indexOfEndPath);
        
        imagePath = imagePath.replace(/%2F/g,"/");
        
        imagePath = imagePath.replace(/%20/g," ");
     
        return imagePath;
    }