Rightnow i'm using a array.map method to upload each file and gets the url in response but the thing is it gives me "C:\fakepath\pic1" in some files which creates a messs although it uploads it correctly(means i've seen the images in my firebase storage) but not get back the url in response
This is the code i'm using to put files
uploadPicsArr.map(function (pic, index) {
var storageRef = fbStorage.ref('images/'+token+'/'+pic.name);
// Upload file to Firebase Storage
var uploadTask = storageRef.put(pic.file);
uploadTask.on('state_changed', null, null, function () {
var downloadUrl = uploadTask.snapshot.downloadURL;
userInfo[pic.name] = downloadUrl;
})
if (uploadPicsArr.length == index + 1) {
fbDatabase.ref('users').push(userInfo).then(function (success){
browserHistory.push('/home');
});
}
})
fbStorage: firebase.storage()
uploadPicsArr = an array of objects and every object has a property name and file
name: name of the selected file
file: selected file
Please tell me what i'm doing wrong or if there's any other better way to upload the whole array and get each file URL in response then it would be better
I think you forget to pass the snapshot as a parameter in the complete function:
uploadPicsArr.map(function (pic, index) {
var storageRef = fbStorage.ref('images/'+token+'/'+pic.name);
// Upload file to Firebase Storage
var uploadTask = storageRef.put(pic.file);
uploadTask.on('state_changed', null, null, function (snapshot) {
userInfo[pic.name] = snapshot.downloadURL;
})
if (uploadPicsArr.length == index + 1) {
fbDatabase.ref('users').push(userInfo).then(function (success){
browserHistory.push('/home');
});
}
})
Related
I am simply trying to test uploading images and I want to display the image, that is uploadoaded.
My code looks like this:
function uploadFile(files){
const storageRef = firebase.storage().ref(); //this references the firebase storage
const horseRef = storageRef.child("horse.jpg");
const file = files.item(0); //will return a list so lets take the first item
const task = horseRef.put(file); //to upload the file we call the put file
console.log(task);
task.then(snapshot => { //returns a buncha data including a snapshot url
const url = snapshot.downloadURL
document.getElementById("upload").setAttribute("src", url)
});
}
But the snapshot.downloadURL is giving back an undefined. Can you help me?
There isn't any downloadURL property on the snapshot which is an UploadTaskSnapshot. You need to use getDownloadURL() method on the storage reference to get the URL. Try refactoring the code as shown below:
task.then(async (snapshot) => {
const url = await snapshot.ref.getDownloadUrl()
document.getElementById("upload").setAttribute("src", url)
});
I would like to ask if is it possible to add data in a nested array.The result i want is this
But i get this when i add a new rating with the code i use
async function getAll(){
const userEmail= firebase.firestore().collection('users')
const snapshot=await userEmail.where('email','==',index.email).get()
if (snapshot.empty) {
console.log('No matching documents.');
return;
}
snapshot.forEach(doc => {
userEmail.doc(doc.id).set({userRatings2:firebase.firestore.FieldValue.arrayUnion({parking:[markerName]})},{merge:true})
userEmail.doc(doc.id).set({userRatings2:firebase.firestore.FieldValue.arrayUnion({rating:[currentRating]})},{merge:true})
console.log(userEmail.doc(doc.id));
});
}
getAll()
Unfortunately in Firebase Firestore you can't even change a simple Array value at a specific index. That means also that you can't save nested array values. You can read more about it on this answer.
The only way to do it is to download the whole Array make your modifications and save the whole array again to the databse. There is not much context of your app so I can't tell if that is a good solution for you. It depends how much data you have in the array.
I've managed to do it by using forEach function to an array of image path
const [imageUri, setImageUri] = useState([]);
const [uploading, setUploading] = useState(false);
const UploadImage = () => {
setUploading(true);
imageUri.forEach(async (image, index) => {
// setTransferred(0);
const pathToFile = image;
let filename = pathToFile.substring(pathToFile.lastIndexOf('-') + 1);
const extension = filename.split('.').pop();
const name = filename.split('.').slice(0, -1).join('.');
filename = name + Date.now() + '.' + extension;
const reference = storage().ref().child(`/userprofile/${filename}`);
// path to existing file on filesystem
// uploads file
const task = reference.putFile(pathToFile);
try {
await task;
const url = await reference.getDownloadURL();
downloadableURI.push(url);
if (index == imageUri.length - 1) {
setUploading(false);
Alert.alert(
'Image uploaded!',
'Your image has been uploaded to the Firebase Cloud Storage Successfully!',
);
}
} catch (e) {
console.log(e);
}
});
};
whenever the function is called, then the array of images is uploaded to firebase storage,
I have the logic of an image uploaded from the Frontend -> I get a download URL and attach it to the users document via a function.
This is the current code:
export const newProfilePictureUploaded = functions.region('europe-west1').storage.object().onFinalize(async (object) => {
if (!object.contentType?.startsWith('image/')) return;
return admin.storage().bucket(object.bucket).file(object.name || '').makePublic().then(async data => {
const filename = object.name as string;
const splitName = filename.split('/');
const folderName = splitName[0];
if (folderName === 'profilePics') {
const uid = splitName[1].substring(0, splitName[1].indexOf('.'));
console.log(uid);
await updateUserAvatar(uid, 'https://storage.googleapis.com/' + object.bucket + '/' + object.name)
return;
}
console.log('No operation for folder ' + folderName);
return
})
})
Now the thing is the image is displayed on the URL, but even if the Image in the Storage Bucket is replaced, then URL still points to that old image. While it should be deleted and the new image should be in that path.
Why dont I use the .getSignedUrl() method? The URL I get back is too long specially for storing it in the RTDB, and the URL can be public so its really unoptimal for me to use that method.
I am getting a zipped file of images and csv files from a user. I need to unzip those files and upload them to Firestore. When I upload the images, I also want to save the path to download the image in an image object which I push later. I want to save the id's of all the image objects that I push and save them in a term object. I want to wait until all my files are uploaded before calling some other functions.
My function though is being called immediately before my termObj is populated. I tried to save promises and wait until all of them resolve but the promise.all is being executed immediately ( it does not wait for promises to get populated in the for loop )
How do I wait for all of my files to be uploaded and have a populated termObj before I call this.printDone()?
async fileChanged(event) {
const file = event.target.files[0];
const self = this;
let promises= [];
let termObj = {
all_images: [],
};
this.zipService.getEntries(file).subscribe( (next) => {
for (const ent of next) {
let filename : string = ent.filename;
const fileType = filename.slice(filename.indexOf("."));
this.zipService.getData(ent).data.subscribe(async function(val) {
let blobFile = new File([val], filename);
self.task = self.storage.upload(self.authService.getUser() + "/" +filename, blobFile);
if( fileType === '.jpg' || fileType === '.jpeg' || fileType === '.png'){
let pathToFile = self.authService.getUser() + '/' + filename;
// URL
await firebase.storage().ref().child( pathToFile ).getDownloadURL().then(function (url) {
let imageObj = {
downloadURL: url,
};
const imagePromise = self.db.collection('images').add(imageObj).then(function(ref){
termObj.all_images.push(ref.id);
console.log(termObj);
});
promises.push(imagePromise);
});
}
}); // end of unzip service that gets data from zipped entry
} // end of for loop looping through files
}); //gets entries from zipped file
await Promise.all(promises).then(()=>{
this.printDone();
console.log(termObj.all_images);
});
} // end of method
=============Edit==========
moving the await Promise.all statement right after the end of the for loop and then console.log the termObj.all_images gives me the same result.
output of console.log(termObj.all_images)
Move this
await Promise.all(promises).then(()=>{
this.printDone();
console.log(termObj.all_images);});
just after closing the for of.
Your problem is caused because the subscribe is asynchronous (you already know that) But that implies that the promises array is empty when this code is reached.
This code should work but no matter what i do, I cant seem to get the downloadURL.
I am using vue js. This is the code for file upload.
And below you can see the image that shows the console log. It saved the image successfully, only problem is I dont get downloadURL, there does not seem to be one.
// upload file
uploadFile(file, metadata) {
if(file === null) return false
let pathToUpload = this.currentChannel.id
// parent means Messages.vue getMessagesRef() that returns either public or private channel
let ref = this.$parent.getMessagesRef()
// getPath() refers to the path below
let filePath = this.getPath() + '/' + uuidV4() + '.jpg'
// upload file
this.uploadTask = this.storageRef.child(filePath).put(file, metadata)
// upload state
this.uploadState = "uploading"
// on upload state change
this.uploadTask.on('state_changed', snapshot => {
console.log('image uploaded/state_changed in storage: ', snapshot)
// Upload en cours
let percent = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
// $("#uploadedFile").progress("set percent", percent)
$(".progress-bar").css("width", percent+'%')
}, error => {
// Error
this.errors.push(error.message)
this.uploadState = 'error'
this.uploadTask = null
}, () => {
// Upload finished
this.uploadState = 'done'
console.log('done upload')
// reset form
this.$refs.file_modal.resetForm()
// recover the url of file
let fileUrl = this.uploadTask.snapshot.downloadURL
console.log('downloadURL(snapshot) from firebase: ', this.uploadTask.snapshot)
// sendFileMessage() will pass file as parameter on upload
this.sendFileMessage(fileUrl, ref, pathToUpload)
})
},
Console.log() result:
Thanks for your help!
According to firebase document, you have to call uploadTask.snapshot.ref.getDownloadURL in completed callback
uploadTask.snapshot.ref.getDownloadURL().then(function(downloadURL) {
console.log('File available at', downloadURL);
});