Firebase Web Storage - upload a file without specifying its name - javascript

I'm using Firebase Storage and everything works great.
How can I upload a file without specifying its name?
So the file will get a unique name by Firebase, like they do in the storage.
This is an example of what i'm using now:
firebase.initializeApp(config);
var fileUpload = document.getElementById("uploadFile").files;
var storageRef = firebase.storage().ref(fileUpload[0].name);
var uploadTask = storageRef.put(fileUpload[0]);
And I want to do someting like this:
firebase.initializeApp(config);
var fileUpload = document.getElementById("uploadFile").files;
var storageRef = firebase.storage().ref();
var uploadTask = storageRef.put(fileUpload[0]);
Appreciate any help you can provide. Thanks.

There is no built-in API to generate file names for you in Firebase Storage.
But similar to what the Firebase Database does, you can easily generate a filename client-side that is statistically guaranteed to be unique.
One way to do this would be to generate a UUID, such as with the guid() function from this answer:
var storageRef = firebase.storage().ref(guid());
Note that you'd lose the filename extension here, which is how Firebase Storage determines the file type. So more likely you'll want to determine the filename based on the local filename but then with something before it to make it unique.
var storageRef = firebase.storage().ref(guid()+fileUpload[0].name);
Given this combination, there's a pretty good chance that just prefixing with the local timestamp is unique already:
var storageRef = firebase.storage().ref(Date.now()+fileUpload[0].name);

Related

Questions about fs.writeFile

I want to use fs.WriteFile in my JS project. I am building an algorithm that outputs random data and I want to give the user the opportunity to save the data as a txt file. I have been able to implement fs.WriteFile in my project, but I have a couple of questions on how to proceed next as the function remains somewhat unclear.
How do I specify that I want to include the contents of various vars? Is it as simple as data = let1 + let2 + let3 and all of the data will be included?
can I add the current date and time in the .txt file name? If so, how?
How do I tell writeFile to save the contents to a .txt file and open a download blob so that people can specify their own download locations?
Thanks in advance!
I've tried looking at basic documentation but its mainly the same: a template using a simple string that saves into the same directory, which is what I don't want.
For you first question, you are correct. You can just combine different string variables into a larger string variable. See the documentation for string concatenation for more information.
For your second question, yes you can. You can get the current date and time with new Date() and turn it into a variety of formats. For file names, using mydate.toISOString() will probably be the most clean.
Here's an example of both of these in practice:
import fs from 'fs';
// Here's some data that we want to put in the file.
const name = "Bob";
const age = 43;
// Create the data we want to put in our file.
const data = name + '\n' + age;
// Let's grab the date and use it as part of our file name.
const date = new Date();
const fileName = `${date.toISOString()}.txt`;
// Call fs.writeFile to put the data in the file.
fs.writeFile(fileName, data, () => {
console.log(`Wrote data to ${fileName}.`);
});
Your third question is more complicated and probably worth a separate post. fs.writeFile can't do this for you. You'll have to come up with some mechanism for the user to enter their own file name and build off of that.
Edit:
To address your question in the comments, you might be a little confused with how NodeJS works. NodeJS runs on the server and doesn't have any way to deal with buttons or UIs by default like browser JavaScript does. It might be helpful to look at the differences between the two. So you won't be able to save it to the downloads folder on a button click.
With that said, we can save the file to the user's Downloads folder with the same script I posted above by adding the path to the Downloads folder to the beginning of the file name.
Here's the code above adjusted to do that:
import fs from 'fs';
import os from 'os'; // NEW
import path from 'path'; // NEW
const name = "Bob";
const age = 43;
const data = name + '\n' + age;
const date = new Date();
const fileName = `${date.toISOString()}.txt`;
// Get the user's home directory.
const homedir = os.homedir();
// Append the Downloads directory and fileName to the user's home directory.
const fullPath = path.join(homedir, 'Downloads', fileName);
// Use fullPath here instead of fileName.
fs.writeFile(fullPath, data, () => {
console.log(`Wrote data to ${fileName}.`);
});

How to change file's metadata in Google Cloud Storage with Node.js

My image's (which is hosted in Google Cloud Storage) metadata has the property named downloaded, if the image has been downloaded, the value inside the downloaded key will be changed from 0 to 1.
The code in https://cloud.google.com/storage/docs/viewing-editing-metadata#storage-view-object-metadata-nodejs shows how to view the metadatas but didn't really cover how to change the metadata.
Is it possible to do so?
Yes, it is possible.
The way to do it is by using the File.setMetadata() method.
For example, to add metadata to an object in GCS:
const file = storage
.bucket(bucketName)
.file(filename)
const metadata = {
metadata: {
example: 'test'
}
}
file.setMetadata(metadata)
// Get the updated Metadata
const get_metadata = file.getMetadata();
// Will print `File: test`
console.log(`File: ${metadata.metadata.example}`)
To update it, you can retrieve the current metadata with the getMetadata() method, modifying it, and updating it with the setMetadata() method .
For example:
const storage = new Storage();
const file = storage
.bucket(bucketName)
.file(filename)
// Get the file's metadata
const [metadata] = await file.getMetadata()
console.log(`File: ${metadata.name}`)
// update metadata
file.setMetadata(metadata.metadata.example='updated')
// Get the updated metadata
const [get_metadata] = await file.getMetadata()
console.log(`File: ${get_metadata.metadata.example}`)

How to use the Javascript File API in React JS to upload a local file

Lets say I have a photo in ./profile-logo.svg that I want to upload to firebase storage. Right now that part of my code looks like this:
import profileLogo from './profile-logo.svg';
...
var file = new File(profileLogo);
var storageRef = firebase.storage().ref();
var propicRef = storageRef.child(`propics/${currentUser.uid}/${file.name}`);
var uploadTask = propicRef.put(file);
This gives the error undefinedFailed to construct 'File': 2 arguments required, but only 1 present. I find the documentation a bit unclear about the 'bits' and 'name' arguments.
What I have working: uploading to firebase from a <input type="file"/> component
Links for reference:
JS File Constructor documentation: https://developer.mozilla.org/en-US/docs/Web/API/File/File
Firebase storage upload file: https://firebase.google.com/docs/storage/web/upload-files
EDIT: when I try sending in a string for the second argument like var file = new File(profileLogo, "propic.svg");, I get an alert that says Failed to construct 'File': The provided value cannot be converted to a sequence.

Expected full URL but got a child path, use ref instead

This is related to this thread, but it's a new problem I encountered. I am trying to add an image to a table cell in HTML, and I'm using Firebase Storage in combination with Firebase Database for this. The idea is to get the image from a gs://xxxxxxxx path in the database and use it in the js, but I get this error in the console:
Firebase Storage: Invalid argument in refFromURL at index 0: Expected full URL but got a child path, use ref instead."
So it seems that the url_ul path is not working. If, for example, I introduce the 'gs://xxxxxxxx' instead of url_ul, it works like a charm. And if I read the value url_ul as a text, I get that path. However, it doesn't work if I have that variable in refFromURL('url_ul')
I have the following js code for this:
var rootRef = firebase.database().ref().child("Test");
var storage = firebase.storage();
rootRef.on("child_added", snap => {
var headline = snap.child("headline").val();
var url_ul = snap.child("imageUrl").val();
var storageRef = storage.refFromURL('url_ul').then(function(url) {
var test = url;
document.querySelector('img').src = test;
}).catch(function(error) {});
$("#table_body").append("<tr><td>" + headline + "</td><td><img src='test' alt='' border=3 height=100 width=100></td></tr>");});
where the database looks like this:
So there is a gs://xxxxx path, which, according to Firebase documentation, should work fine:
// Create a reference from a Google Cloud Storage URI
var gsReference = storage.refFromURL('gs://bucket/images/stars.jpg')
Any idea what is wrong here?
To make things more clear:
This line works perfectly fine:
var storageRef = storage.refFromURL("gs://nameofapp.appspot.com/armonii_culturale.png").getDownloadURL().then(function(url) ...
But this one doesn't
var storageRef = storage.refFromURL("url_ul").getDownloadURL().then(function(url) ...
And it's strange because "url_ul" should contain the same value.

How to send image from firebase storage to Microsoft Emotion API (Cognitive Service)

I am storing images uploaded on the application on firebase storage. I then need to retrieve the image and send it to Microsoft's Cognitive Service (emotion API). I tried sending the download URL of an image to the API but it doesn't take - it gives me a 400 error. How can I send an image from firebase storage to the Emotion API.
Below, is the code that stores the uploaded file to firebase storage... I need to continue the code at the end of this code snippet.
download_photo_btn.addEventListener("click", function(e) {
var user = firebase.auth().currentUser;
var uid;
if (user != null) {
uid = user.uid; // The user's ID, unique to the Firebase project. Do NOT use
// this value to authenticate with your backend server, if
// you have one. Use User.getToken() instead.
}
var snap = takeSnapshot();
var blob = dataURItoBlob(snap);
// Create a root reference
var storageRef = firebase.storage().ref();
// Initial UID for images
var selfieID = 0;
// Create a reference to 'mountains.jpg'
var selfieRef = storageRef.child(uid + '-' + selfieID++ + '.png');
// Create a reference to 'images/mountains.jpg'
var selfieImagesRef = storageRef.child('/selfies/' + uid + '-' + selfieID++ + '.png');
// While the file names are the same, the references point to different files
selfieRef.name === selfieImagesRef.name // true
selfieRef.fullPath === selfieImagesRef.fullPath // false
// send image file to firebase storage
var file = blob;
var uploadTask = selfieImagesRef.put(file);
});
You have two options:
Since you already have it handy, you can upload the same blob to the Emotion API. This does mean that you will upload your image data twice, once to Firebase and once to Microsoft.
You can get a public URL for your storage item. This is the relevant documentation. Note that you may need to adjust the permission of your storage for Cognitive Services to access the image.
Some additional info here: firebase storage - getting image URL

Categories