I have this issue and can't figure out how to solve it, addDoc() and setDoc() functions separately without using "if" "else" work correctly, but when I use "if" "else" it gives me this error.
"Error adding product to cart: TypeError: Cannot read properties of undefined (reading 'quantity')"
It is a function to add a product to the cart, it must check if the document is already in the subcollection, then increase quantity +1, otherwise create a document, taking the name of the product as the document id.
I'am using Vue.js 3 and Firebase 9.
const productRef = doc(db, "carts", cartId, "cartProducts", this.productName);
const productDoc = await getDoc(productRef);
if (productDoc.exists) {
await updateDoc(productRef, {
quantity: productDoc.data().quantity + 1
});
} else {
await setDoc(productRef, product);
}
The error
Error adding product to cart: TypeError: Cannot read properties of
undefined (reading 'quantity')
indicates that the field quantity is undefined in the productDoc.
So either you enforce through security rules that quantity has a correct value when the productDoc doc is created/updated or you adapt your code to handle this case as follows, for example:
const productRef = doc(db, "carts", cartId, "cartProducts", this.productName);
const productDoc = await getDoc(productRef);
console.log(JSON.stringify(productDoc.data()));
if (productDoc.exists && productDoc.data().quantity) {
await updateDoc(productRef, {
quantity: productDoc.data().quantity + 1
});
} else {
await setDoc(productRef, product);
}
solved using runTransaction
import { runTransaction } from "firebase/firestore";
const productRef = doc(db, "carts", cartId, "cartProducts", this.productName);
try {
await runTransaction(db, async (transaction) => {
const newQ = await transaction.get(productRef);
if (!newQ.exists()) {
await setDoc(productRef, product);
throw " Document no exist ";
}
const newQuant = newQ.data().quantity + 1;
transaction.update(productRef, { quantity: newQuant });
});
console.log("Transaction successfully committed!");
} catch (e) {
console.log("Transaction failed: ", e);
}
Related
I am building to do list and I have complete button where I want to toggle true or false state and updating in firebase. I was searching on the platform, there were simillar solutions but not exacly what I needed.
So far I have this function:
const completedHandler = (id) => {
const docRef = doc(db, "todos", id);
updateDoc(docRef, {
isCompleted: !initialValues.isCompleted
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error.message);
});
};
The problem is that this is updating the state only once, and it won't change it again, for example if the state is false, it is updating in firebase as true, and that's it.
I am not sure where is the issue. Any help is appreciate.
Since the value that you write to the database depends on the current value of the field in the database, you'll need to first read the data and then write the new value based on that. The best way to do this is with a transaction and would look something like:
import { runTransaction } from "firebase/firestore";
try {
const docRef = doc(db, "todos", id);
await runTransaction(db, async (transaction) => {
const todoDoc = await transaction.get(docRef);
if (!todoDoc.exists()) {
throw "Document does not exist!";
}
const newValue = !todoDoc.data().isCompleted;
transaction.update(docRef, { isCompleted: newValue });
});
console.log("Transaction successfully committed!");
} catch (e) {
console.log("Transaction failed: ", e);
}
I have some code that gets a collection reference to the users collection and then queries an animeID field whether it contains a certain value or not. I want to change this and only query inside the document with the id i pass. So if you look at the picture of my firestore you can see that i have two documents inside the users collection each with their unique id. I want to query for the animeID field only in the document that i want. Not all the documents as it does right now. How would i go about doing this? I have tried using doc and then passing in the id of the document but i don't think query works on doc as it gives me an error. Thanks
const docRef = collection(db, 'users')
const q = query(docRef, where('animeID', 'array-contains', parseInt(id)))
onSnapshot(q, (snapshot) => {
let results = []
snapshot.docs.forEach((doc) => {
results.push({...doc.data(), id: doc.id})
})
if(results.length > 0){
console.log(true)
}
else{
console.log(false)
}
}, (error) => {
console.log(error)
})
Firestore structure:
You need to do as explained in the doc:
import { doc, getDoc } from "firebase/firestore";
const docRef = doc(db, "users", "dbmbEiR6....");
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
const animeID = docSnap.data().animeID;
// Do whatever you want with animeID
// E.g. log its value:
console.log(JSON.stringify(animeID));
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
So you don't need to declare a Query in this case. Just declare a DocumentReference and use the getDoc() method.
The error happens in this code:
document.querySelector('.adding').onclick = async function adding() {
const output = document.querySelector('.added')
const translate = collection(db, "translate")
await setDoc(translate, {
eng_tot,
sank_tot
});
output.innerText = 'Added'
console.log('added', english, sanskrit)
english.value = ''
sanskrit.value = ''
eng_tot = []
sank_tot = []
setTimeout(() => {
output.innerText = ''
}, 2000);
};
** I am trying from 2 days but can't understand what's the problem !!**
I am trying to add an array in firebase , i am tring so many solution but can't get what's the problem !!
The setDoc() function takes a DocumentReference as first parameter but you are passing a CollectionReference. If you want to add a document with random ID then use addDoc() instead:
import { collection, addDoc } from "firebase/firestore"
const translate = collection(db, "translate")
await addDoc(translate, {
eng_tot,
sank_tot
});
If you want to specify the document ID yourself, then use doc() to create a document reference and then use setDoc():
import { doc, setDoc } from "firebase/firestore"
const translateDoc = doc(db, "translate", "custom_doc_id")
await setDoc(translateDoc, {
eng_tot,
sank_tot
});
We have a booking app that uses Vuejs and Cloud Firestore (client library web version 9).
Scenario: Two customers come to our booking site at the same time and try to book the last available package at the same time. To save the reservation, we are using firestore transactions. However, if we try to book the last package from two devices and hit the submit button "simultaneously", the code below allows both orders to be accepted. Also, the package "sold" field is only incremented. Is there any way we can improve the following code to prevent overbooking?
const packageDocRef = doc(db, ...);
try {
const orderId = await runTransaction(db, async (transaction) => {
const packageDoc = await transaction.get(packageDocRef);
if (!packageDoc.exists()) {
throw "Package does not exist!";
}
const quantity = packageDoc.data().quantity;
const sold = parseInt(packageDoc.data().sold + 1);
if (quantity >= sold) {
transaction.update(packageDocRef, { sold: increment(1) });
const orderRef = await addDoc(collection(db, collections.ORDERS), reservation);
if(orderRef.id){
dispatch ("saveTravellerDetails", { orderId: orderRef.id });
return orderRef.id;
}else{
throw "Error saving reservation!";
}
} else {
return Promise.reject("Sorry! Not enough spots available.");
}
});
console.log("Reservation created ");
return { orderId: orderId };
} catch (e) {
// This will be a "Not enough spots available" error.
console.error(e);
return { error: e };
}
Ok, I saw the error in my ways. I'm posting here in the event it can help someone else.
Instead of await addDoc(collection(db, collections.ORDERS), reservation);
I needed to use transaction.set(orderDocRef, reservation);
All I want to do is to get a row (so called 'doc') from a data base.
so far, I have tried:
all with the 'aref'
const aref = firebase
.firestore()
.collection("polja")
.where("id", "==", match.params.id);
console.log(aref);
function getIt() {
const item = [];
setLoading(true);
aref.get().then((doc) => {
const data = doc.data();
setItem(item);
console.log(item);
setLoading(false);
});
}
useEffect(() => {
getIt();
}, []);
this gave the following error:
To get a single document, you must specify the document ID:
firebase.firestore().collection("polja").doc(documentId).get().then((snapshot) => {
console.log(snapshot.data())
}).catch((e) => console.log(e))
Also you should not use .where() to get just a single document, but there is an issue I found in your original code.
If you look carefully, the parameter in .where() is a string "match.params.id". That seems to be a dynamic value being fetched from somewhere else. Please remove the quotes and try again.
firebase.firestore().collection("polja").where("id", "==", match.params.id).get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
Try adding a catch block as shown which might help catch any errors. Make sure your security rules also allow you to fetch the data.
Also if any error is logged in the console, share a screenshot of it.
To get single document form firebase firestore you should first know if you are using the modular firebase 9.+ version or firebase version < 9.
In new modular firebase firestore(version 9.+) it should be like this:
import { getFirestore, collection, query, getDocs } from 'firebase/firestore'
async read(id) {
const firestore = getFirestore()
const docRef = doc(firestore, this.collectionPath, id)
const docSnap = await getDoc(docRef)
const data = docSnap.exists() ? docSnap.data() : null
if (data === null || data === undefined) return null
return { id, ...data }
}
If you are using not modular Firebase firestore( < version 9) then the same function should look something like this:
async read(id) {
const result = await (await firestore())
.collection(this.collectionPath)
.doc(id)
.get()
const data = result.exists ? result.data() : null
if (data === null || data === undefined) return null
return { id, ...data }
}