Search code examples
javascriptfirebasegoogle-cloud-platformgoogle-cloud-firestorefirebase-storage

Upload Folder of Images to Firestore Storage and Put Download URLs in Firestore


I have roughly 10,000 images that I want to upload to Firebase Storage (it adds up to around 800mb).

Using Javascript, I am looking for a way to:

  1. Upload them to Firebase Storage
  2. Grab their URL upon upload and create Cloud Firestore documents for each using their file names with a field called "downloadURL" or something like that that my website can then use for tags.

So say one file is 4670.jpg. I want to upload the file, grab its persistent URL and then create a Cloud Firestore document called 4670 that has a text field with it's persistent URL. I know how to do this for a single file, but I'm dealing with thousands.

Edit: A huge thanks for, Renaud Tarnec who gave me a working solution

HTML

// File selector

<input type="file" multiple onchange="processSelectedFiles(this)">

// CDN for Firebase, Cloud Firestore, and Firebase Storage
<script src="https://www.gstatic.com/firebasejs/4.12.0/firebase.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.11.0/firebase-firestore.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.12.0/firebase-storage.js"></script>

<script>
  // Initialize Firebase
  var config = {
    apiKey: "********************",
    authDomain: "********************",
    databaseURL: "********************",
    projectId: "********************",
    storageBucket: "********************",
    messagingSenderId: "********************"
  };
  firebase.initializeApp(config);


var db = firebase.firestore();

</script>

<script src="script.js"></script>

Javascript

function processSelectedFiles(fileInput) {
  var files = fileInput.files;

  var promises = []

  for (var i = 0; i < files.length; i++) {

    var file = files[i] 

      promises.push(uploadAndSavePromise(file))
  }

    Promise.all(promises);
}

function uploadAndSavePromise(file) {
     var storageRef = firebase.storage().ref();
     var fileName = file.name
     // Remove extension
     var trimmedFileName = fileName.slice(0, -4)

     var imageRef = storageRef.child('test/'+fileName);

    return imageRef.put(file).then(function(snapshot) {

        db.collection("maincollection").doc(trimmedFileName).set({
        imageURL: snapshot.downloadURL,

})

});

}

Solution

  • You say that you know how to do for one single file.

    You probably have a process based on promises which does something like (in pseudo code):

    ({Upload_to_Firebase_Storage_Promise})
    .then(function(urlOfFile) {
        {create__Firestore_doc_Promise}
    })
    .catch(....)
    

    What you should do is to use Promise.all() following this pattern (a mix of JavaScript and pseudo code):

    var promises = [];
    
    {forEach file to upload} (
      //Create a Promise that upload the file and save the url and add this promise to the array, as follow
      promises.push(uploadAndSavePromise(fileToUpload))
    )
    
    //and call    
    Promise.all(promises);
    

    where uploadAndSavePromise is a function implementing the initial promise chain:

    function uploadAndSavePromise(file) {
        return ({Upload_to_Firebase_Storage_Promise(file)})
        .then(function(urlOfFile) {
            {create__Firestore_doc_Promise}
        });
    }
    

    Now, one thing that I would consider is how is this is going to work if you want to upload 10000 images in a row...