Reputation: 1841
FirebaseStorage always returns error 400
when I try to delete a directory i.e. something like the following always returns error 400
.
let storageRef = FIRStorage.storage().reference().child("path/to/directory")
storageRef.deleteWithCompletion { (error) in
print("error: \(error)") // always prints error code 400
}
However, deleting a file works fine e.g. something like doesn't return an error:
let storageRef = FIRStorage.storage().reference().child("path/to/file.jpg")
storageRef.deleteWithCompletion { (error) in
print("error: \(error)") // works fine, error is nil
}
What could I be doing wrong here? I don't reckon it's not supported by FirebaseStorage because deleting files from a directory one by one would be pretty lame (specially if the said directory has 100s or 1000s of these).
Upvotes: 51
Views: 42021
Reputation: 1818
You can list a folder and delete its contents recursively:
deleteFolder(path) {
const ref = firebase.storage().ref(path);
ref.listAll()
.then(dir => {
dir.items.forEach(fileRef => this.deleteFile(ref.fullPath, fileRef.name));
dir.prefixes.forEach(folderRef => this.deleteFolder(folderRef.fullPath))
})
.catch(error => console.log(error));
}
deleteFile(pathToFile, fileName) {
const ref = firebase.storage().ref(pathToFile);
const childRef = ref.child(fileName);
childRef.delete()
}
Upvotes: 28
Reputation: 670
Empty folder deletes itself. So deleting all the files from the folder would delete the folder itself too.
Upvotes: 2
Reputation: 4603
Do not do this at home!
Firebase 9
Example how to delete folder using client side:
async function deleteFolder(path: string) {
const folderRef = ref(storage, path)
const fileList = await listAll(folderRef)
const promises = []
for(let item of fileList.items) {
promises.push(deleteObject(item))
}
const result = await Promise.all(promises)
return result
}
Upvotes: 0
Reputation: 567
I have noticed that when deleteing all the files in a firebase storage folder, after a while, the folder is also deleted. No action required.
Upvotes: 0
Reputation: 922
Now you know we cant delete folder in firebase storage. But you can list file inside that folder and remove each file.
Here a sample..
// Create a root reference
var storageRef = firebase.storage().ref();
// Create a reference
var mountainsRef = storageRef.child("your root path");
// Now we get the references of these files
mountainsRef.listAll().then(function (result) {
result.items.forEach(function (file) {
file.delete();
});
}).catch(function (error) {
// Handle any errors
});
Flutter firebase storage listAll()
method is currently available in the dev version of the package, in version 5.0.0-dev.1
, which you can use as shown above.
Upvotes: 11
Reputation: 3804
In 2020, deleting Firebase Storage folder seems to just work. I just did, in my Cloud Functions (Node.js Admin), below and it deletes folder, sub-folders, and files in them. I did download Google Cloud Storage using npm, but I didn't import that library in anyway physically, and it seems Firebase Storage is now supporting this feature unlike what everyone said above. Maybe they have updated it. I tested it that it is working.
admin.initializeApp({
storageBucket: "bucket_name.appspot.com",
})
const bucket = admin.storage().bucket();
await bucket.deleteFiles({
prefix: `${folderName}/`
});
Upvotes: 32
Reputation: 1130
Based on TheFastCat's answer and Teodor Ciuraru's comment I created the below Firebase Cloud Function, which deletes a user's folder when the user is deleted from Firebase Authentication.
const admin = require('firebase-admin')
const functions = require('firebase-functions')
const bucket = admin.storage().bucket()
exports.deleteUser = functions.auth.user().onDelete(async (user) => {
const { uid } = user
await bucket.deleteFiles({
prefix: `${uid}/`
})
})
Upvotes: 7
Reputation: 1494
A modern version of 'Miki' answer, using ES2018 Async/Await
with for await... of..
and deleted files counter.
const storage = firebase.storage();
const deleteFile = async (filePath) => {
const ref = storage.ref(filePath);
return await ref.delete();
};
const deleteFolderRecursive = async (folderPath) => {
const ref = storage.ref(folderPath);
const list = await ref.listAll();
let filesDeleted = 0;
for await (const fileRef of list.items) {
await deleteFile(fileRef.fullPath);
filesDeleted++;
}
for await (const folderRef of list.prefixes) {
filesDeleted += await deleteFolderRecursive(folderRef.fullPath);
}
return filesDeleted;
};
// Usage
async deleteFolder(x) {
try {
const filesDeleted = deleteFolderRecursive('path/to/storage/folder');
console.log(`${filesDeleted} files has been deleted`);
// you can now, for instance, unblock the UI at this point
} catch(err){
// probably denied permissions or 'path/to/storage/folder' is not a folder
console.error(err)
}
}
As mentioned before, folders references are not deleted but at least they do not drag from your storage quota like unreachable files do.
Upvotes: 1
Reputation: 471
A way to do this could be the following (with the last file, gets rid of dir):
let ref = firebase.storage().ref(path);
ref.listAll().then(dir => {
dir.items.forEach(fileRef => {
var dirRef = firebase.storage().ref(fileRef.fullPath);
dirRef.getDownloadURL().then(function(url) {
var imgRef = firebase.storage().refFromURL(url);
imgRef.delete().then(function() {
// File deleted successfully
}).catch(function(error) {
// There has been an error
});
});
});
}).catch(error => {
console.log(error);
});
Upvotes: 6
Reputation: 84
It seems that the only way to delete a directory is to loop through all files and delete them one by one:
async function DeleteFirebaseStorageFolder(directoryName: string) {
const serviceAccount = require('../secret/adminSdkPrivateKey.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
storageBucket: 'gs://yourprojectname.appspot.com'
});
const bucket = admin.storage().bucket();
const files = (await bucket.getFiles({ directory: folderName }))[0];
const Deletions = [];
files.forEach(file => {
Deletions.push(bucket.file(file.name).delete());
})
await Promise.all(Deletions);
bucket.getFiles({ directory: folderName }).then((files) => {
console.log('Remaining number of files: ' + (files[0].length).toString());
})
}
DeleteFirebaseStorageFolder('myDirectoryName');
Upvotes: 0
Reputation: 436
Here is one solution to delete files in a folder in Firebase Storage using Firebase Functions.
It assumes you have models stored under /MyStorageFilesInDatabaseTrackedHere/path1/path2 in your Firebase Database.
Those models will have a field named "filename" which will have the name of the file in Firebase Storage.
The workflow is:
(Disclaimer: the folder in Storage is still leftover at the end of this function so another call needs to be made to remove it.)
// 1. Define your Firebase Function to listen for deletions on your path
exports.myFilesDeleted = functions.database
.ref('/MyStorageFilesInDatabaseTrackedHere/{dbpath1}/{dbpath2}')
.onDelete((change, context) => {
// 2. Create an empty array that you will populate with promises later
var allPromises = [];
// 3. Define the root path to the folder containing files
// You will append the file name later
var photoPathInStorageRoot = '/MyStorageTopLevelFolder/' + context.params.dbpath1 + "/" + context.params.dbpath2;
// 4. Get a reference to your Firebase Storage bucket
var fbBucket = admin.storage().bucket();
// 5. "change" is the snapshot containing all the changed data from your
// Firebase Database folder containing your models. Each child has a model
// containing your file filename
if (change.hasChildren()) {
change.forEach(snapshot => {
// 6. Get the filename from the model and
// form the fully qualified path to your file in Storage
var filenameInStorage = photoPathInStorageRoot + "/" + snapshot.val().filename;
// 7. Create reference to that file in the bucket
var fbBucketPath = fbBucket.file(filenameInStorage);
// 8. Create a promise to delete the file and add it to the array
allPromises.push(fbBucketPath.delete());
});
}
// 9. Resolve all the promises (i.e. delete all the files in Storage)
return Promise.all(allPromises);
});
Upvotes: 1
Reputation: 3464
From the context of a secure google cloud function - you can delete an entire directory using the Google Cloud Storage npm package (aka Google Cloud Storage API) like so:
const gcs = require('@google-cloud/storage')();
const functions = require('firebase-functions');
...
const bucket = gcs.bucket(functions.config().firebase.storageBucket);
return bucket.deleteFiles({
prefix: `users/${userId}/`
}, function(err) {
if (err) {
console.log(err);
} else {
console.log(`All the Firebase Storage files in users/${userId}/ have been deleted`);
}
});
more documentation available on GCS API docs
Upvotes: 36
Reputation: 3549
As stated above, deleting a directory is not valid. I'm sharing an example of querying a list of files in Firebase Database and deleting them one by one. This is my query and call.
let messagePhotoQuery = messagesRef.child(group.key).child("messages").queryOrdered(byChild: "photoURL")
deleteMessagePhotos(from: messagePhotoQuery)
This is my function looping through getting the URL, then deleting the file at that storage reference.
func deleteMessagePhotos(from photoQuery: FIRDatabaseQuery) {
photoQuery.observeSingleEvent(of: .value, with: { (messagesSnapshot) in
guard messagesSnapshot.exists() else { return }
print(messagesSnapshot)
for message in messagesSnapshot.children {
let messageSnapshot = message as! FIRDataSnapshot
let messageData = messageSnapshot.value as! [String: AnyObject]
if let photoURL = messageData["photoURL"] as? String {
let photoStorageRef = FIRStorage.storage().reference(forURL: photoURL)
photoStorageRef.delete(completion: { (error) in
if let error = error {
print(error)
} else {
// success
print("deleted \(photoURL)")
}
})
}
}
})
}
Upvotes: 0
Reputation:
In 26/5/2017 there is no way to delete directory But you can use my algorithm
Use this code.
this.sliders = this.db.list(`users/${this.USER_UID}/website/sliders`) as FirebaseListObservable<Slider[]>
/**
* Delete image from firebase storage is take a string path of the image
* @param _image_path
*/
deleteImage(_image_path: string) {
// first delete the image
const storageRef = firebase.storage().ref();
const imageRef = storageRef.child(_image_path);
imageRef.delete().then(function() {
console.log('file deleted');
// File deleted successfully
}).catch(function(error) {
// Uh-oh, an error occurred!
console.log(error);
});
}
/**
* Deletes multiple Sliders, it takes an array of ids
* @param ids
*/
deleteMutipleSliders(ids: any) {
ids.forEach(id => {
this.getSliderDetails(id).subscribe(slider => {
let id = slider.$key; // i think this is not nesesery
const imgPath = slider.path;
this.deleteImage(imgPath);
});
return this.sliders.remove(id);
});
}
Upvotes: 1
Reputation: 1841
from google group, deleting a directory is not possible. You have to maintain a list of files somewhere (in Firebase Database) and delete them one by one.
https://groups.google.com/forum/#!topic/firebase-talk/aG7GSR7kVtw
I have also submitted the feature request but since their bug tracker isn't public, there's no link that I could share.
Upvotes: 20