Trouble updating Doc in Firestore with React - reactjs

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()

Related

State Not Finished Setting before being used in useEffect

I am hosting a react app in aws amplify using the aws-serverless version of express as the REST API, which sits inside of a lambda function. A big problem that I am facing is that asynchronous jobs in aws-serverless express cause the lambda function to complete before the promises resolve. Leaving me with no data and no error handling. This caused me to bring a lot of the asynchronous work to the front end of the application.
The problem here is that I need to bring a large amount of data into state. Right now, I am using a delay workaround (shown below) but instead need a programatic way to make sure state is finished updating before being used in the second useEffect hook (dependent on odds & failedTries props) instead of using the delay functionality.
Any help would be greatly appreciated.
const App = ({ signOut }) => {
const [odds, setOdds] = useState([]);
const [updateTime,setUpdateTime] = useState(0);
const [failedTries,setFailedTries] = useState(0);
useEffect(() => {
const setNflOdds = async () => {
let response = await updateNflOdds();
let data = response;
setOdds(data);
};
setNflOdds();
setUpdateTime(1);
const interval = setInterval(() => {
setNflOdds();
setUpdateTime(updateTime => updateTime +1);
}, 100000);
return () => clearInterval(interval);
}, []);
useEffect(() => {
const s3Push = (() => {
if(!odds.length) {
setFailedTries(failedTries => failedTries + 1);
} else {
const delay = ms => new Promise(res => setTimeout(res, ms));
const nflOddsRefDelay = async() => {
*//This is the current workaround, wait ten seconds before pushing odds state up to the s3 bucket*
await delay(10000);
oddsS3Helper(odds);
};
nflOddsRefDelay()
}
});
s3Push();
}, [odds, failedTries]);
With the above indicated delay workaround this works for my use case (13k records inside of the array) but the data size is highly variable and I want to figure out a way that no matter the data size it brings the entire call up to the s3 bucket.
below is the content of the functions being called in the useEffect hook
const pushToS3 = async ( file, key ) => {
const creds = await Auth.currentCredentials()
const REGION = {region};
const s3Client = new S3Client({
credentials: Auth.essentialCredentials(creds),
region: REGION
});
const params = {
Bucket: {s3 bucket name}
Key: key,
Body: file,
};
s3Client.send(new PutObjectCommand(params));
console.log("file is sent");
};
const oddsS3Helper = (async (odds) => {
console.log("inside s3 helper: ",odds);
let csv = '';
let headers = Object.keys(odds[0]).join(',');
let values = odds.map(odd => Object.values(odd).join(',')).join('\n');
csv += headers + '\n' + values;
const buffedFile = csv;
const key = 'nflprops.csv'
const delay = ms => new Promise(res => setTimeout(res, ms));
const propRefDelay = async() => {
await delay(5000);
await postNflOdds();
};
pushToS3( buffedFile, key );
await propRefDelay();
});
async function getNflGames() {
const apiName = {name of serverless API inside of lambda};
const path = {path name};
const init = {
headers: {} // OPTIONAL
};
const data = await API.get(apiName, path, init);
return data;
};
async function getNflOdds(gameId) {
const apiName = {name of serverless API inside of lambda};
const path = {path name};
const init = {
headers: {}, // OPTIONAL
body: { gameId }
};
const data = await API.post(apiName, path, init);
return data;
};
async function updateNflOdds() {
const ojNflGames = await getNflGames();
const nflGameProps = [];
const nflOddsPush = ( async () => {
try {
await ojNflGames.data.map( async (game) => {
const ojNflOdds = await getNflOdds(game.id)
await ojNflOdds.data[0].odds.map((line) => {
nflGameProps.push(
{
gameId: game.id,
oddsId: line.id,
sports_book_name: line.sports_book_name,
name: line.name,
price: line.price,
checked_date: line.checked_date,
bet_points: line.bet_points,
is_main: line.is_main,
is_live: line.is_live,
market_name: line.market_name,
home_rotation_number: line.home_rotation_number,
away_rotation_number: line.away_rotation_number,
deep_link_url: line.deep_link_url,
player_id: line.player_id,
}
);
});
});
} catch (err) {
console.log("there was an error", err);
}
});
try {
await nflOddsPush();
} catch(err) {
console.log("odds push errored: ", err);
}
console.log("inside of updateNflOdds function: ",nflGameProps);
return nflGameProps;
};

firebase query with where getting FirebaseError

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)

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();
}, []);

Deletion in FireStore (Latest Snip)

I have a Data Table i want to delete every document inside collection before invoke loadCheckOut.
How can i dow that with latest JS Syntax.
I am using React JS, and it initilize DB from getDb() method so methods like db.collection() not work on it i want a complete moduler solution
const loadCheckout = async (priceId) => {
//before adding we must delete existing collection
const docRef_x = collection(db, `customers/${user.uid}/checkout_sessions`);
const snapshot = await getDocs(docRef_x);
const x = await deleteDoc(snapshot);
const docRef = await addDoc(
collection(db, `customers/${user.uid}/checkout_sessions`),
{
price: priceId,
success_url: window.location.origin,
cancel_url: window.location.origin,
}
);
const ref = collection(db, `customers/${user.uid}/checkout_sessions`);
const snap = onSnapshot(
ref,
{ includeMetadataChanges: true },
async (doc) => {
var error = null,
sessionId = null;
var first = true;
doc.forEach((ele) => {
if (first) {
error = ele.data().error;
sessionId = ele.data().sessionId;
first = false;
}
});
console.log(sessionId);
if (error) {
alert(error);
}
if (sessionId) {
const stripe = await loadStripe(stripe_public_key);
stripe.redirectToCheckout({ sessionId });
}
}
);
};
This won't work:
const snapshot = await getDocs(docRef_x);
const x = await deleteDoc(snapshot);
The deleteDoc function requires a single DocumentReference, while your snapshot is a QuerySnapshot. This has very little to do with the change in syntax, as snapshot.delete() also wouldn't have worked in v8 of the SDK and earlier.
To delete the documents in the query snapshot, loop over the results and delete them one by one:
snapshot.forEach((doc) => {
deleteDoc(doc.ref);
});

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.

Resources