How to query a single document by custom parameter and update it in Firebase 9 - javascript

I have a custom ID in my Firebase documents. I want to get a single document querying by that custom ID and modify it. I'm using firebase v9.
Here's my code so far:
const toggleLike = async () => {
const q = query(collection(db, 'mixrCocktails'), where('id', '==', cocktailId))
const querySnapshot = await getDocs(q)
const result: any[] = []
querySnapshot.forEach(doc => result.push(doc.data()) )
if (!isLiked) {
await updateDoc(result[0], { userLikes: arrayUnion(publisherId) })
setIsLiked(true)
}
else {
await updateDoc(result[0], { userLikes: arrayRemove(publisherId) })
setIsLiked(false)
}
}
The query works fine, but the problem is when I run updateDoc . I get the following error:
Uncaught (in promise) FirebaseError: Expected type 'Zu', but it was: a custom Object object
I tried running result[0].update({ userLikes: arrayUnion(publisherId) }) and I get Uncaught (in promise) TypeError: result[0].update is not a function.
I've also tried
const docRef = doc(db, "mixrCocktails", cocktail.id)
await updateDoc(docRef, { userLikes: arrayUnion(publisherId) })
And I get
Uncaught (in promise) TypeError: n.indexOf is not a function
In the docs (https://firebase.google.com/docs/firestore/manage-data/add-data) I see they use a document ref in the following way:
import { doc, updateDoc, arrayUnion, arrayRemove } from "firebase/firestore";
const washingtonRef = doc(db, "cities", "DC");
// Atomically add a new region to the "regions" array field.
await updateDoc(washingtonRef, {
regions: arrayUnion("greater_virginia")
});
In the example, I understand "DC" is the ID Firebase sets for the document. But how can I create a ref by querying for another field different than that?
Full code can be found here: https://github.com/coccagerman/mixr
Thanks in advance!

Based on your question, if I understand it correctly. You want to query a document using where before updating the document result.
You're not referencing the updateDoc() properly. Check the snippet that I wrote based on your snippet above. Here's some options:
Using .map:
const q = query(collection(db, 'mixrCocktails'), where('id', '==', cocktailId));
const querySnapshot = await getDocs(q);
const documents = querySnapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() }));
for (const document of documents) {
// console.log(document.id);
const documentRef = doc(db, 'mixCocktails', document.id);
if (!isLiked) {
await updateDoc(documentRef, { userLikes: arrayUnion(publisherId) })
setIsLiked(true)
}
else {
await updateDoc(documentRef, { userLikes: arrayRemove(publisherId) })
setIsLiked(false)
}
}
Using async method:
async function updateDocuments (document) {
// console.log(document.id);
const documentRef = doc(db, 'mixrCocktails', document.id);
if (!isLiked) {
await updateDoc(documentRef, { userLikes: arrayUnion(publisherId) })
setIsLiked(true)
}
else {
await updateDoc(documentRef, { userLikes: arrayRemove(publisherId) })
setIsLiked(false)
}
}
const q = query(collection(db, 'mixrCocktails'), where('id', '==', cocktailId));
const querySnapshot = await getDocs(q);
querySnapshot.forEach((document) => {
updateDocuments(document);
});
You may still improve the written code above for your use-case.

Related

How to query in a specific document in Firebase

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.

Make query with "where" filter in Firestore

I want to filter and get specific items based on the categoryID, where i use the "where" method and the "==" operator.
I have this Firestore collection called "task", where the documents are divided by userID and each document for a user contains an array of different tasks. The structur is seen here:
Enter image description here
This is how i add the array tasks for an user in the task collection:
const addToFirebase = async() => {
if(dataFetch) {
await setDoc(doc(db, "task", `${firebase.auth().currentUser.uid}`), {
tasks: tasks
}, {merge: true});
}
}
And this is how i have tried to make my query that is not working:
const getFilteredTasks = async() => {
const collectionRef = collection(db, "task", `${firebase.auth().currentUser.uid}`, "tasks");
const q = query(collectionRef, where("categoryID", "==", item.id));
console.log('outside snapshot')
console.log(item.id)
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
console.log(doc.data());
console.log('inside snapshot')
});
}
When the above function is called, it logs the "outside snapshot" and the correct item.id, which is the categoryID for each task, but it does not log the doc.data() and the "inside snapshot".
You've set up your query as though each task will be a separate document in a collection, but based on the screenshot and the way you're setting the data, you just have a single document per user. That document contains all the individual tasks. So to access that you would get the document and use client side code to use the parts of the data you care about:
const getFilteredTasks = async () => {
const docRef = doc(db, 'task', `${firebase.auth().currentUser.uid}`);
const snapshot = await getDoc(docRef);
const data = snapshot.data();
if (!data) {
return [];
} else {
return data.tasks.filter(task => task.categoryID === item.id);
}
}

getDocs - firebase react native

I want to get a document and to update.
I tried used this code, but he dont accept the "idDoc":
const Doc = query(collection(database, "user_veic"),where("email", "==", auth.currentUser?.email),where("kmF", "==", ""));
getDocs(Doc).then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(`${doc.id} => ${doc.data()}`);
const idDoc = doc.id
})
})
.then(
updateDoc(doc(database, "user_veic", idDoc), {
kmF: "teste1",
km: "teste1",
}))
^^^^: FirebaseError: Invalid document reference. Document references must have an even number of segments, but user_veic has 1
I tried this:
const Doc = query(collection(database, "user_veic"),where("email", "==", auth.currentUser?.email),where("kmF", "==", ""));
getDocs(Doc).then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(`${doc.id} => ${doc.data()}`);
const idDoc = doc(database, "user_veic", doc.id)
updateDoc(idDoc, {
kmF: "teste1",
km: "teste1",
})
})
})
^^^^: [Unhandled promise rejection: TypeError: doc is not a function. (In 'doc(database, "user_veic", doc.id)', 'doc' is an instance of lh)]
What did i do wrong?
In your first code example, you declare const idDoc inside of the callback parameter to .forEach(). That variable does not exist outside of the callback function. You then try to use it in the updateDoc() in a completely different block of code. It is undefined at that point, thus you are getting an error that you aren't passing enough parameters.
In your second code example, which is much closer to what you want to do, based on the error message it looks like you aren't importing doc with the rest of the Firestore functions from firebase/firestore.
RESOLVIDO #Greg thank you
const Doc = query(collection(database, "user_veic"),where("email", "==", auth.currentUser?.email),where("kmF", "==", ""));
getDocs(Doc).then((querySnapshot) => {
let values = null;
querySnapshot.forEach((doc) => {
console.log(`${doc.id} => ${doc.data()}`);
values = doc.id;
});
var transactionUpdate = database.collection("user_veic").doc(values);
transactionUpdate.update({
kmF: kmF,
})
})

How to get a single doc with React/Firestore?

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 }
}

Firebase Firestore: How to get ref from snapshot via using async/await

I am using Cloud Firestore in Firebase functions with Node.js 8
Simple open question is: Does it possible to get ref from .get() via using async/await?
Example:
const snapshot = await db.collection(/*..*/).doc(/*..*/).get();
const data = snapshot.data();
const ref = /* ???? */
// Then using...
ref.update({/*..*/});
or should I just do like?
const ref = db.collection(/*..*/).doc(/*..*/);
const snapshot = await ref.get();
/* so on.../*
If you are trying to get a new reference from your snapshot constant then its possible
I would so it this way
example
const areaSnapshot = await admin.firestore().doc("areas/greater-boston").get()
const bostonCities = areaSnapshot.data().cities;
const allAreas = await areaSnapshot.ref.parent.doc("new-york").get()
const nyCities= allAreas.data().cities
console.log(bostonCities, nyCities)
update document
//to update document
const areaSnapshot = await admin.firestore().doc("areas/greater-boston").get()
const allAreas = areaSnapshot.ref.parent.doc("new-york").update({
capital: {
liberty: true
}
})
await allAreas
.then(() => {
console.log("success")
})
.catch(err => console.log(err))
Source:
https://firebase.google.com/docs/firestore/manage-data/add-data

Categories

Resources