FirebaseError: Function updateDoc() called with invalid data - reactjs

I'm writing a function uploadPost() inside that function I add a doc into firebase firestore collection than I choose a image and update doc by getting download url from firebase but I getting error like
FirebaseError: Function updateDoc() called with invalid data. Unsupported field value: a custom Promise object (found in field image in document posts/mcux46HsSK4mxycOIuev)
My function is given below
const uploadPost = async () => {
if (loading) return;
setLoading(true);
const docRef = await addDoc(collection(db, 'posts'), {
username: session.user.username,
caption: captionRef.current.value,
profileImg: session.user.image,
timestamp: serverTimestamp(),
})
const imageRef = ref(storage, `posts/${docRef.id}/image`);
await uploadString(imageRef, selectedFile, 'data_url').then(async (snapshot) => {
const downloadUrl = getDownloadURL(imageRef);
await updateDoc(doc(db, 'posts', docRef.id), {
image: downloadUrl
});
});
setOpen(false);
setLoading(false);
setSelectedFile(null);
}
What is wrong with that please give some suggestions for this.

const uploadPost = async () => {
if (loading) return;
setLoading(true);
const docRef = await addDoc(collection(db,'posts'), {
username: data?.user?.username,
caption: captionRef.current.value,
profileImg: data?.user?.image,
timestamp: serverTimestamp(),
})
const storage = getStorage(app);
const imageRef = ref(storage, `posts/${docRef.id}/image`);
await uploadString(imageRef, selectedFile, "data_url").then(async () => {
const downloadURL = await getDownloadURL(imageRef);
console.log('this is it' , downloadURL);
await updateDoc(doc(db, 'posts', docRef.id) , {
image: downloadURL,
})
}).catch((err) => {console.log(err)})
setOpen(false);
setLoading(false);
setSelectedFile(null);
}

Related

i am trying to store the photo in the database (firebase) and in the storage. the photo got store in the Storage, but not added in the firestore

I am trying to store the photo in the database (firebase) and in the storage simultaneously. The photo got store in the Storage, but not added in the firestore. Any Help Please ?
My code below shows what I did to perform the task. Oh it is in reactJs
function Preview() {
const cameraImage = useSelector(selectCameraImage);
const navigate = useNavigate();
const dispatch = useDispatch();
// if there is no Image taken then return to homepage (navigate('../'), {replace:
true})
useEffect(()=>{
if(!cameraImage){
navigate('../', {replace: true});
}
}, [navigate, cameraImage])
const closePreview = ()=>{
dispatch(resetCameraImage())
}
const sendPost = () =>{
const id = uuid();
const uploadTask = storage
.ref(`posts/ ${id}`)
.putString(cameraImage, "data_url");
uploadTask.on('state_changed', null, (error) =>{
//error function
console.log(error);
},
//COMPLETE function**this is the storage*## storage ##
()=>{storage
.ref('post')
.child(id)
.getDownloadURL()
.then((url) => {
db.collection('posts').add({
imageUrl: url,
username: 'yannick Simo',
read: false,
//profilePic
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
});
navigate('./chats', {replace: true});
})
})
}
return (
<div className="preview" >
<div onClick={sendPost} className="preview__footer">
<h2>Send Now</h2>
<SendIcon fontSize="small" className="preview__sendIcon" />
</div>
</div>);
}
export default Preview;
You're calling getDownloadURL on a different ref than you're uploading the image to.
The upload goes to
const uploadTask = storage
.ref(`posts/ ${id}`)
.putString(cameraImage, "data_url");
And then you get the download URL like this:
storage
.ref('post')
.child(id)
.getDownloadURL()
Note posts (plural) vs post (singular) in these references.
To prevent such mistakes, I recommend creating a single variable to hold the reference, and then using that everywhere:
const sendPost = () => {
const id = uuid();
const uploadRef = storage.ref(`posts/ ${id}`); // 👈
const uploadTask = ref.putString(cameraImage, "data_url"); // 👈
uploadTask.on('state_changed', null, (error) => {
//error function
console.log(error);
},
() => {
ref.getDownloadURL() // 👈
.then((url) => {
db.collection('posts').add({
imageUrl: url,
username: 'yannick Simo',
read: false,
//profilePic
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
});
navigate('./chats', {
replace: true
});
})
})
}
As a final improvement, since you're not doing anything in the other callbacks, you can also just the fact that uploadTask is a promise itself, and use then() on it, to shorten the code and make it a bit more idiomatic:
const sendPost = () => {
const id = uuid();
const uploadRef = storage.ref(`posts/ ${id}`);
const uploadTask = ref.putString(cameraImage, "data_url");
uploadTask.then(() => { // 👈
ref.getDownloadURL()
.then((url) => {
db.collection('posts').add({
imageUrl: url,
username: 'yannick Simo',
read: false,
//profilePic
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
});
navigate('./chats', {
replace: true
});
})
}).catch((error) => console.error(error)); // 👈
}
If you then use async/await of modern JavaScript, you can turn this into the even simpler to read:
const sendPost = () => async { // 👈
const id = uuid();
const uploadRef = storage.ref(`posts/ ${id}`);
await ref.putString(cameraImage, "data_url"); // 👈
const url = await ref.getDownloadURL() 👈
db.collection('posts').add({
imageUrl: url,
username: 'yannick Simo',
read: false,
//profilePic
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
});
navigate('./chats', {
replace: true
});
}

Problem with uploading multiple images in Firebase v9

I have a problem with uploading multiple images in Firebase v9! It works but only with 1 image, even though I'm mapping through my array.
Everything works as I expect until the last part where it doesn't perform the uploading task for every image...
What am I doing wrong? Thank you in advance!
Here my code:
const addImagePost = () => {
for(let i = 0; i < event.target.files.length; i ++) {
const newImage = event.target.files[i]
setSelectedFiles((prevState => [...prevState, newImage]))
}
}
const uploadPost = async (e) => {
e.preventDefault()
if(loadingPost) return;
setLoadingPost(true)
const docRef = await addDoc(collection(db, 'posts'), {
userID: user?.userUID,
username: user?.userName,
caption: inputPost,
profileUser: user?.userPhoto,
timestamp: serverTimestamp()
})
const imageRef = ref(storage, `files/${docRef.id}/image`)
// It only displays the last image of the array
selectedFiles?.map(async(file) => (
await uploadBytes(imageRef, file, 'data_url').then(async () => {
const downloadURL = await getDownloadURL(imageRef)
await updateDoc(doc(db, 'posts', docRef.id), {
image: downloadURL
}, {merge: true})
})
))

Upload multiple images to firebase then save image url to firestore

Can someone assist me with revising the code so it will wait for the upload to finish then save the image urls to firestore? I'm new to async and await and can't seem to figure it out. The fileDownloadUrl is still empty even if I do the saving to firestore inside the Promise.all(promises).then():
cxonst promises = [];
const fileDownloadUrl = [];
pictures.forEach(file => {
const uploadTask =
firebase
.storage()
.ref()
.child(`img/upl/${file.data.name}`)
.put(file.uploadTask);
promises.push(uploadTask);
uploadTask.on(
firebase.storage.TaskEvent.STATE_CHANGED,
snapshot => {
const progress = Math.round((snapshot.bytesTransferred /
snapshot.totalBytes) * 100);
if (snapshot.state === firebase.storage.TaskState.RUNNING) {
console.log(`Progress: ${progress}%`);
}
},
error => console.log(error.code),
async () => {
const downloadURL = await
uploadTask.snapshot.ref.getDownloadURL();
fileDownloadUrl.push(downloadURL);
}
);
});
Promise.all(promises)
.then(() => {
db
.collection("properties")
.add({
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
title: title,
description: description,
pictures: fileDownloadUrl,
user: user.uid
})
})
.catch(err => console.log(err));
While you are waiting for the promises of the put calls to complete, you're then using the uploadTask.on() to determine the download URL. Since this on is not part of the promise, there is no guarantee they're in sync.
A simpler and working approach should be:
const promises = pictures.map(file => {
const ref = firebase.storage().ref().child(`img/upl/${file.data.name}`);
return ref
.put(file.uploadTask)
.then(() => ref.getDownloadURL())
});
Promise.all(promises)
.then((fileDownloadUrls) => {
db
.collection("properties")
.add({
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
title: title,
description: description,
pictures: fileDownloadUrls,
user: user.uid
})
})
.catch(err => console.log(err));

How to fetch one document from Firebase and how to pass the id to delete it?

this is my react native + firebase project and i have got 2 questions:
How do you suggest to pass the id from one CV ?
How do i fetch only one CV from firebase, cause if i try this it gives me this error:
TypeError: undefined is not an object (evaluating 'querySnapshot.docs.map')]
fetching all the documents from the collection is fine
getCv: () => {
const id = "eccc137b-88be-470d-a0b8-c90b58a6473a"
return firebase
.firestore()
.collection('cvs')
.doc(id)
.get()
.then(function(querySnapshot) {
let cvs = querySnapshot.docs.map(doc => doc.data())
// console.log(doc.data())
return cvs
})
.catch(function(error) {
console.log('Error getting documents: ', error)
})
}
This is my fetchCV method
fetchCvs = async () => {
try {
const cvs = await this.props.firebase.getCv()
//const cvs = await this.props.firebase.getCvs()
//console.log(cvs)
this.setState({ DATA: cvs, isRefreshing: false })
} catch (e) {
console.error(e)
}
}
This is how i add one CV
onSubmit = async () => {
try {
const cv = {
photo: this.state.image,
title: this.state.title,
description: this.state.description,
salary: this.state.salary,
createdAt: new Date().toISOString()
}
this.props.firebase.uploadCv(cv)
this.setState({
image: null,
title: '',
description: '',
salary: '',
createdAt: ''
})
} catch (e) {
console.error(e)
}
}
uploadCv: cv => {
const id = uuid.v4()
const uploadData = {
id: id,
cvPhoto: cv.photo,
cvTitle: cv.title,
cvDescription: cv.description,
cvSalary: cv.salary,
cvCreatedAt: cv.createdAt
}
return firebase
.firestore()
.collection('cvs')
.doc(id)
.set(uploadData)
},
and This is how i implemented the deleteCv method
onDelete = async () => {
const cvId = {
id: this.state.title
}
//this.props.firebase.deleteItem(cv);
const deleteId = this.props.firebase.deleteItem(cv);
console.log(deleteId)
}
I have different error, when I try similar code in nodejs, but I think its the same reason. In line:
let cvs = querySnapshot.docs.map(doc => doc.data())
As you are using get on DocumentReference querySnapshot is instance of DocumentSnapshot which does not have property docs. I think you should use querySnapshot.data() first and than manipulate on data returned.
Or maybe you wanted to use get on collection, not on document, and than you will get QuerySnapshot object and .doc array will be available.

How to make Async Await Function in React Native?

I want to create a function that is about uploading photo to Firebase Storage with react-native-fetch-blob. I'm using Redux and you can find action functions below:
My problem is that uploadImage function is not running like asynchronous. Firebase function is running before uploadImage, so application give me an error.
I think i can't make a asynchronous function. How can i fix it ?
uploadImage() function:
const uploadImage = async (imageSource, whereToUpload) => {
let imageURL = '';
const mime = 'image/jpg';
const { Blob } = RNFetchBlob.polyfill;
const { fs } = RNFetchBlob;
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
window.Blob = Blob;
console.log('URI =>', imageSource.uri);
let imgUri = imageSource.uri;
let uploadBlob = null;
const imageRef = firebase.storage().ref(whereToUpload + '/' + imageSource.fileName);
const uploadUri = Platform.OS === 'ios' ? imgUri.replace('file://', '') : imgUri;
await fs.readFile(uploadUri, 'base64')
.then((data) => Blob.build(data, { type: `${mime};BASE64` }))
.then((blob) => {
uploadBlob = blob;
return imageRef.put(blob, { contentType: mime });
})
.then(() => {
uploadBlob.close();
// eslint-disable-next-line no-return-assign
return imageURL = imageRef.getDownloadURL();
})
.catch((error) => {
console.log(error);
});
return imageURL;
};
and the main action is:
export const addProjectGroup = (
myUser,
groupName,
groupDescription,
groupProfilePic,
) => dispatch => {
const groupProfileFinalPic = async () => {
let finalGroupPicture = { landscape: '' };
if (_.isEmpty(groupProfilePic.src)) {
await uploadImage(groupProfilePic, 'groupPictures').then((imageURL) => {
console.log('Ä°ÅžLEM TAMAM!');
console.log('SELECTED IMAGE URL =>', imageURL);
finalGroupPicture.landscape = imageURL;
});
} else {
finalGroupPicture.landscape = groupProfilePic.src.landscape;
}
return finalGroupPicture;
};
console.log("final group profile pic =>", groupProfileFinalPic());
// Önce grubu yaratalım..
// eslint-disable-next-line prefer-destructuring
const key = firebase
.database()
.ref()
.child('groups')
.push().key;
firebase
.database()
.ref('/groups/' + key)
.set({
admin: {
email: myUser.email,
name: myUser.name,
uid: myUser.uid,
},
groupName,
groupDescription,
groupProfilePic: groupProfileFinalPic(),
projects: '',
})
.then(() => {
console.log('Groups oluÅŸturuldu.');
})
.catch(e => {
Alert.alert('Hata', 'Beklenmedik bir hata meydana geldi.');
console.log(e.message);
});
dispatch({
type: ADD_PROJECT_GROUP,
});
};
You are not awaiting groupProfileFinalPic(). This should be done before creating the action you want to dispatch.
groupProfileFinalPic().then(groupProfilePic => {
return firebase
.database()
.ref("/groups/" + key)
.set({
admin: {
email: myUser.email,
name: myUser.name,
uid: myUser.uid
},
groupName,
groupDescription,
groupProfilePic,
projects: ""
})
.then(() => {
console.log("Groups oluÅŸturuldu.");
})
.catch(e => {
Alert.alert("Hata", "Beklenmedik bir hata meydana geldi.");
console.log(e.message);
});
});
I have no clue what the last dispatch is for, you might want to do that in one of the callbacks. Your code is to verbose for an SO question, but I hope this helps anyways.
You are using both await and then on the same call. To use await, you can arrange it something like
const uploadImage = async (imageSource, whereToUpload) => {
...
try {
let data = await RNFS.fs.readFile(uploadUri, 'base64')
let uploadBlob = await Blob.build(data, { type: `${mime};BASE64` }))
...etc...
return finalResult
catch (e) {
// handle error
}
}

Resources