2

Is there a way in Firebase Storage to generate a download url pointing to nothing, in order to upload a file to that url later? something like that (in Kotlin):

    fun generateItemPhotoUrl(id: String) =
        storageRef.child("$Id/${generateUniqueName()}.${COMPRESS_FORMAT.name}").downloadUrl

This code returns a failed task...

I want this so my upload process can look like so:

// Case: old photo is null but new one is not - upload new photo to a new uri
generateItemPhotoUrl(itemId).continueWithTask { generateTask ->
    if (generateTask.isSuccessful)  {
        val destUrl = generateTask.result.toString()

        // Uploading may take time, so first update document to hold a uri, so consecutive
        // calls will result in updating instead of uploading a new file
        updateItemPhoto(itemId, destUrl).continueWithTask { updateTask ->
            if (updateTask.isSuccessful) 
                uploadFileToDest(destUrl, newImage).continueWithTask { uploadTask ->
                    if (!uploadTask.isSuccessful) updateItemPhoto(itemId, null)
                }
        }
    }
}

As explained in code, I need this to prevent the case of updating the item's photo twice in a row too fast for the first one to finish it's upload. I end up with 2 files - one of them is not referenced from anywhere. If I could do something like this, the second upload will go to my "update" case (instead of the "new photo" case presented here) - where the file will be switched correctly.

Omer Levy
  • 347
  • 4
  • 11

1 Answers1

2

Is there a way in Firebase Storage to generate a download URL pointing to nothing, in order to upload a file to that URL later?

No, this is not possible. You cannot generate a Storage URL in advance and upload the file sometime later. You get the download URL only when the file is successfully uploaded on the Firebase servers. This is because the URL that comes from the UploadTask contains a token that is generated on the server, and it's apart of the URL. To get the entire download URL of an uploaded file, please see my answer from the following post:

The process of uploading the file is asynchronous, meaning that any code that needs that URL, needs to be inside the" onSuccess()" method, or be called from there. So there is no need to upload the file twice.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • Ok, I see. So, is there a way to achieve safe consecutive uploads? (Safe from the possibility of orphan files) – Omer Levy Jan 27 '21 at 08:55
  • I'm not sure what do you mean by "orphan files", but if an upload succeeds, then it will be safe to use its URL. – Alex Mamo Jan 27 '21 at 09:20
  • I mean that if I upload a file and save to the respective document in Firestore, and then I upload another file for the same item before the first one finishes, I will get two files in Storage with only one uri in Firestore (as the second one will override the first one). I need a way to determine that a file is currently uploading for this item. – Omer Levy Jan 27 '21 at 17:50
  • Yes, you'll get the behavior if you overwrite the URL on the same property. For example, if you have a property in the document called imageUrl, when you upload the first image, the URL is added to that property. When you add the second image, when you get the URL, if you write it on the same property, you'll end up having two images with only one URL, which is not correct. The best option that you have is to add each URL to an array of URLs. That way you can store multiple URLs without overwriting the old one. Right? – Alex Mamo Jan 27 '21 at 17:56
  • That means I'll have to upload-get-set. I guess that's possible, I'll try it. Thanks. – Omer Levy Jan 27 '21 at 18:01
  • Yes, it's possible, each image should be added as a separate file in Cloud Storage, and each corresponding URL added as a separate URL in a property of type array. – Alex Mamo Jan 27 '21 at 18:03
  • If I already have a file with a url that is saved in my document, is it possible to overwrite it with a new file and save the document update? – Omer Levy Jan 27 '21 at 18:11
  • No, it's not. If the property is of type String, you should change it to be of type array, and right after use [FieldValue.arrayUnion("imageUrl")](https://firebase.google.com/docs/firestore/manage-data/add-data#update_elements_in_an_array) to update it. – Alex Mamo Jan 27 '21 at 18:18
  • No, I mean not changing anything in the document. Just uploading a different image to the same uri so now the uri I already have will show a different file. I already do that with users' profile pictures so I know it works, but I am asking if it's good practice for items that might have multiple pictures: if one picture is switched with a new one - can I just use the same uri, or is it bad practice for some reason? – Omer Levy Jan 27 '21 at 22:42
  • No, you cannot switch to a new URL. Each image has it's own distinct URL. – Alex Mamo Jan 28 '21 at 01:13
  • I'm not switching to a new url - I am changing the content of the same url. I upload a different image to the same path and it overrides the previous one. – Omer Levy Jan 28 '21 at 08:29
  • In that case, use different IDs for each image. Don't use the same ID, as it will be overwritten. – Alex Mamo Jan 28 '21 at 13:42