firebase query with where getting FirebaseError - reactjs

I'm using "firebase": "^9.9.0", so web version 9 syntax. I'm trying to get a document by its field value, and im having no luck. I can get all the documents in the collection but every way I try to use .where I get errors, this is the main error i get:
FirebaseError: Expected type 'ba', but it was: a custom Pa object.
Here is my latest attempt:
const router = useRouter()
const paletteData = router.query
const [palette, setPalette] = useState([])
useEffect(() => {
const docRef = query(collection(db, 'palettes'), where("slug", "==", "03045e-0077b6-00b4d8-90e0ef-caf0f8"));
const docSnap = getDoc(docRef)
if (docSnap.exists()) {
setPalette(docSnap.data())
console.log("Document data:", docSnap.data());
} else {
console.log("No such document!");
}
}, [router])
Another attempt was:
useEffect(() => {
getDoc(doc(db, "palettes"), where("slug", "==", paletteData.palette)).then(docSnap => {
if (docSnap.exists()) {
console.log("Document data:", docSnap.data());
} else {
console.log("No such document!");
}
})
}, [router])
Note, slug is a field inside of the document in the palette collection.

Might not be the best solution but after messing around, I got this to work:
const { user } = params
const userData = []
const userRef = collection(db, 'users')
const q = query(userRef, where('uid', '==', user), limit(1))
const userDoc = await getDocs(q)
userDoc.forEach((doc) => {
userData.push(doc.data())
})
console.log(userData)

Related

useEffect didnt run

So i have this function that i want to run once when the app start. This function task is to create userId then i will run another function to fetch data from firebase with the userId that created before. But the fetch function didn't start or it didnt do the task well, there is no sign of error, that's what make it more confusing. If i press the fetch function by button it work correctly.
the state
const [task, setTask] = useState(); // bisa di sebut sebagai controller text input
const [taskItems, setTaskItems] = useState([]); // state untuk list task
const [userId, setUserId] = useState();
const [isLoading, setIsLoading] = useState(true);
const baseUrl =
'https://react-http-post-RANDOM_KEY-default-rtdb.firebaseio.com/task/' + userId;
this is function to create userId function on init app
const handleCreateUser = async () => {
setIsLoading(true);
try {
const value = await AsyncStorage.getItem('userId');
if (value !== null) {
setUserId(value);
} else {
const uniqueId = makeid(6);
await AsyncStorage.setItem('userId', 'user' + uniqueId);
setUserId('user' + uniqueId);
}
await fetchDatabase();
} catch (error) {
console.log('errorrr AsyncStorage' + error);
}
setIsLoading(false);
};
this is function to fetch data from firebase
const fetchDatabase = async () => {
console.log('infinite looping');
try {
const response = await fetch(baseUrl + '.json');
if (!response.ok) {
throw new Error('Something went wrong!');
}
const data = await response.json();
// looping Map/Object dengan key sebagai indexnya
const loadedTask = [];
for (var id in data) {
loadedTask.push({
key: id,
text: data[id].text,
isComplete: data[id].isComplete,
});
}
setTaskItems(loadedTask);
} catch (error) {
setError(error.message);
}
};
this is how i call the useEffect
useEffect(() => {
handleCreateUser();
}, []);
The first thing I see is that you are not using await correctly. It should be before fetchDatabase(); function that is inside handleCreateUser like so:
await fetchDatabase();
The word await is there when you have to call an asynchronous function and you have to wait for this function to be completed.
Edit
To use only one useEffect you can check if your fetch function received your data by:
// or whatever statusCode you get when the data are present
if(reponse.statusCode === 200) {
// the await is not needed because it is present for the reponse abov
const data = response.json();
// looping Map/Object dengan key sebagai indexnya
const loadedTask = [];
for (var id in data) {
loadedTask.push({
key: id,
text: data[id].text,
isComplete: data[id].isComplete,
});
}
setTaskItems(loadedTask);
}
i got the answer, by using 2 useEffect
useEffect(() => {
handleCreateUser();
}, []);
useEffect(() => {
fetchDatabase();
}, [userId]);

Trouble updating Doc in Firestore with React

Im trying to edit a document in my firestore db. I get an error i cant figure out.
Uncaught (in promise) FirebaseError: Expected type 'va', but it was: a custom Fh object
Im passing in an Object to the updateDoc function using the spread operator.
const saveEvent = React.useCallback(() => {
console.log(isChecked)
const checked = [];
isChecked.map((item, index) => {
if (item === true) {
checked.push(index + 1)
}
})
console.log(checked)
const newEvent = {
id: tempEvent.id,
title: popupEventTitle,
description: popupEventDescription,
start: popupEventDate[0].toString(),
end: popupEventDate[1].toString(),
allDay: popupEventAllDay,
status: popupEventStatus,
color: selectedColor,
resource: checked
};
if (isEdit) {
// update the event in the list
const index = myEvents.findIndex(x => x.id === tempEvent.id);
const newEventList = [...myEvents];
newEventList.splice(index, 1, newEvent);
console.log(newEventList)
setMyEvents(newEventList);
// ISSUE IS IN THE UpdateEvent function
const UpdateEvent = async () => {
const userRef = collection(database, 'events');
const q = query(userRef, where('id', '==', `${tempEvent.id}`));
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
console.log(newEvent)
updateDoc(doc, {
...newEvent,
});
})
}
UpdateEvent()
} else {
// add the new event to the list
setMyEvents([...myEvents, newEvent]);
const getEvents = async () => {
try {
const docRef = await addDoc(collection(database, "events"), {
id: tempEvent.id,
title: popupEventTitle,
description: popupEventDescription,
start: new Date(popupEventDate[0]),
end: new Date(popupEventDate[1]),
allDay: popupEventAllDay,
status: popupEventStatus,
color: selectedColor,
resource: checked
});
console.log("Document written with ID: ", docRef.id);
} catch (e) {
console.error("Error adding document: ", e);
}
}
//console.log(newEvent)
getEvents()
}
setSelectedDate(popupEventDate[0]);
setOpen(false);
}, [isEdit, myEvents, popupEventAllDay, popupEventDate, popupEventDescription, popupEventStatus, popupEventTitle, tempEvent, selectedColor, isChecked]);
Im not sure whats wrong, and googling the issue gives me little to work with. I cant find anything about Expected type 'va', but it was: a custom Fh object anywhere. Not even in the documentation..
Any help greatly appreciated.
EDIT:
Ater logging doc.query i noticed a small Va on the top of the document. Also a small "$h" when logging doc Anyone know anything more about that?
Screenshots:
This occurs when you're updating a document with incorrect document reference. You should use ref property to get the document reference to properly update the document on your foreach loop. See snippet below:
const UpdateEvent = async () => {
const userRef = collection(database, 'events');
const q = query(userRef, where('id', '==', `${tempEvent.id}`));
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
console.log(newEvent)
// Here. You shouldn't use the doc object itself.
// You must use the `reference` property to get the document reference to update to.
updateDoc(doc.ref, {
...newEvent,
});
})
}
UpdateEvent()
For more information, you may checkout this documentation.
// ISSUE IS IN THE UpdateEvent function
const UpdateEvent = async () => {
const userRef = collection(database, 'events');
const q = query(userRef, where('id', '==',${tempEvent.id}));
if you are using 'where' claouse then you will always get one doc
const querySnapshot = await getDocs(q);
const doc = await getDocs(q); try this
querySnapshot.forEach((doc) => {
console.log(newEvent)
updateDoc(doc, {
...newEvent,
});
})
}
UpdateEvent()
Try this
// ISSUE IS IN THE UpdateEvent function
const UpdateEvent = async () => {
const userRef = collection(database, 'events');
const q = query(userRef, where('id', '==', `${tempEvent.id}`));
const doc = await getDocs(q);
//querySnapshot.forEach((doc) => {
console.log(newEvent)
updateDoc(doc, {
...newEvent,
//});
})
}
UpdateEvent()

ReactJS: await function for fetching data returns a pending promise

I'm trying to fect data from a firebase database.
However, I have subcollections so I need to first get the id of the document and then get the docs inside the subcollection :
collection --> doucments --> subcollection --> documents
I use this :
const [data, setData] = useState([]);
useEffect(() => {
const fecthData = async () => {
try {
const querySnapshot = await getDocs(collection(db, "users"))
querySnapshot.forEach((doc) => {
console.log(doc.id, "=>", doc);
var querySnap = await getDocs(collection(db, `users/${doc.id}/general`))
console.log(querySnap)
});
}catch(err) {
console.log(err)
}
};
fecthData();
}, []);
This returns the following error :
Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError: F:\panel_admin\src\pages\Management.js: Unexpected reserved word 'await'. (26:26)
Removing "await" does return the needed data put in a pending promise ?
How can I get the data normaly like the first document ?
Use for...of. The problem is forEach((doc) function is not async.
useEffect(() => {
const fetchData = async () => {
try {
const querySnapshot = await getDocs(collection(db, "users"))
let allDocs = [];
querySnapshot.forEach((doc) => {
allDocs.push({...doc.data(), id: doc.id});
})
for (const item of allDocs) {
const querySnap = await getDocs(collection(db, `users/${item.id}/general`))
console.log(querySnap)
}
}catch(err) {
console.log(err)
}
};
fetchData();
}, []);

What am I doing wrong to get an array from firebase

I have this function in WorkoutController.js
export async function getFavourites(FavRetrived) {
var FavList = []
var snapshot = await firebase
.firestore()
.collection("Favourites")
.doc(firebase.auth().currentUser.uid)
.collection("userFavourites")
.get()
snapshot.forEach((doc) => {
const favDoc = doc.data()
favDoc.id = doc.id
FavList.push(favDoc)
})
FavRetrived(FavList)
}
I used basically flatlists to get the datas from the collection and it works good but now I want to use the id's array to do some controls.
I think the second part of the code it creates an array of id but I don't know how to use it or show it.
in Screen.js I have
import { getFavourites } from '../context/WorkoutController'
const [FavList, setFavList] = useState()
useEffect(() => {
getDataFav()
}, [])
function getDataFav() {
getFavourites(FavRetrieved)
}
function FavRetrieved(FavList) {
setFavList(FavList)
}
Like this if I use a flatlist passing FavList as data I can see all the elements of the collection, but what if I want to show just the first id of the array?
I don't want to use where function, I need to see the datas as an array, for example something like FavList[0].name (but this doesn't work)
First, we need to tweak getFavourites so that it handles the case where the user isn't logged in with a meaningful error and it shouldn't use callbacks if you are making use of async/await syntax - just use Promise chaining instead.
export async function getFavourites() {
const user = firebase.auth().currentUser;
if (!user)
return Promise.reject(new Error("User must be signed in first"));
const favList = []
const snapshot = await firebase
.firestore()
.collection("Favourites")
.doc(user.uid)
.collection("userFavourites")
.get()
snapshot.forEach((doc) => {
const favDocData = doc.data()
favDocData.id = doc.id
favList.push(favDocData)
})
return favList
}
You would then use it in your component like so:
import { getFavourites } from '../context/WorkoutController'
// status of favList
const [status, setStatus] = useState("loading")
// array of favourites
const [favList, setFavList] = useState()
// error message to show user
const [errorMsg, setErrorMsg] = useState("")
useEffect(() => {
let disposed = false
getFavourites()
.then((newFavList) => {
if (disposed) return // component discarded, do nothing.
setFavList(newFavList)
setErrorMsg("")
setStatus("fetched")
})
.catch((err) => {
if (disposed) return // component discarded, do nothing.
console.error("getFavourites failed: ", err)
setErrorMsg("Failed to get favourites")
setStatus("error")
});
// return cleanup function
return () => disposed = true
}, []);
if (status === "loading")
return (<Spinner />)
if (status === "error")
return (<div key="error">{errorMsg}</div>)
// if here, favList is now an array of favourite documents data
return ( /* ... render favList ... */ )
export async function getFavourites(FavRetrived) {
var FavList = []
var snapshot = await firebase
.firestore()
.collection("Favourites")
.doc(firebase.auth().currentUser.uid)
.collection("userFavourites")
.get()
snapshot.forEach((doc) => {
const favDoc = doc.data();
const id = doc.id;
FavList.push({ id, ...favDoc })
})
FavRetrived(FavList)
}
You can access it by FavList[0].id

React js throwing Firestore Missing or insufficient permissions even after Rules are public

Following is code for my firestore writing
When I try to write to my Firestore database, I get Missing or insufficient permissions error. Even after I changed the rules to public.
iam using npm firebase package in my project
import React, { useState, useEffect } from 'react'
import { myFirebaseStorage, myFirebaseFirestore, timestamp } from '../firebase/config';
const useStorage = (file) => {
const [progress, setProgress] = useState(0);
const [error, setError] = useState(null);
const [url, setUrl] = useState(null);
useEffect(() => {
const storageRef = myFirebaseStorage.ref(file.name);
//database collection reference
const collectionRef = myFirebaseFirestore.collection('images');
storageRef.put(file).on('state_changed', (snap) => {
let percentage = (snap.bytesTransferred / snap.totalBytes) * 100;
setProgress(percentage);
},
(err) => {
setError(err);
},
async () => {
const url = await storageRef.getDownloadURL();
console.log(" Image URL: ", url);
const createdAt = timestamp();
//writing data to firestore
collectionRef.add({ url: url, createdAt: createdAt })
.then((docRef) => {
console.log("Document written with ID: ", docRef.id);
})
.catch((error) => {
console.error("Error adding document: ", error);
});
collectionRef
.get()
.then(snapshot => {
// allowed for an admin user
console.log("got it ")
})
.catch(error => {
// a non-admin user is denied list permission
console.log(error.message);
});
setUrl(url);
}
)
}, [file])
return (
{ progress, url, error }
)}export default useStorage
As you also reference your Firebase Storage, you'll need to set up Firebase Storage Security rules as well for the write to work.

Resources