Hello I want to update a field in a firebase document.
Right now , I am accessing the document collection like this
However I am having trouble setting teh shares field of the doc to shares+=1 ?
What am i doing wrong here in the set method?
const buyStock = async () => {
const q = await query(
collection(db, 'myStocks'),
where('ticker', '==', props.name)
);
const querySnapshot = await getDocs(q);
if (!querySnapshot.empty) {
// simply update the record
querySnapshot.forEach((doc) => {
doc.id.set({
shares: doc.id.data().shares+=1
})
// doc.data() is never undefined for query doc snapshots
console.log(doc, doc.id, ' => ', doc.data());
});
You're almost there. To update a document, you need a reference to that document. You can get this with:
querySnapshot.forEach((doc) => {
doc.ref.update({
shares: doc.data().shares+=1
})
});
You can also use the built-in atomic increment operator:
doc.ref.update({
shares: increment(1)
})
It looks like you are calling the set method on the 'id' field. Try to remove that. So just do
doc.set({
shares: doc.data().shares+=1
})
give that a shot. If that doesn't work, i'd try updating a document that is not part of a query snapshot.
Related
I have a problem, i have a Firebase Firestore Database connected to my React.JS Project, where users can enroll to courses. Now if i'm trying to load the users collection from the DB it returns 1 entry.
const fetchAthletes = async () => {
debugger
try {
const athletes: Array<any> = [];
const athleteRef = collection(db, COLLECTION_NAME_ATHLETE);
const getAthleteQuery = query(athleteRef, where('user', '==', userAuthToken.accessToken));
const querySnapshot = await getDocs(getAthleteQuery)
if (querySnapshot.docs) {
//this for each gets skipped, even when querySnapshot.doc has values in it
querySnapshot.forEach((doc) => {
athletes.push({
id: doc.id,
...doc.data()
});
setAthletes(athletes as Array<Athlete>);
})
}
} catch (error: unknown) {
enqueueSnackbar((error as string), { variant: 'error', autoHideDuration: 3000 })
}
}
But when i want to loop over it via array.prototype.map it always skips it.
I debbuged through the funtion and found out that docs from Firestore is set with values tbat i wanna recieve.
Data returned by Firestore
I have no clue why it doesn't work. Any idea or help is appreciated
Rather than attempt to individually set each doc into state, build up your array and set the entire thing into state
const querySnapshot = await getDocs(getAthleteQuery);
setAthletes(querySnapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
}));
I'm currently ripping my hair out trying to query a nested collection in my Firestore db.
my db is set up as follows:
users (collection)
- username
- displayName
- ratedItems (collection)
- itemId
- timestamp
- likedItem
I want to be able to add/update the rated item in the ratedItems collection for a specific user but I seem to be hitting 2 problems:
I assume the query is incorrect as if(querySnapshot.empty) always returns false even if there are no matching items (matching the itemId) in the ratedItems collection, so it always attempts to add a new item which results in duplicate entries in the collection.
if I force the code to bypass the conditional it throws an error when it attempts to update the existing item:
Expected type 'mc', but it was: a custom yc object
My thoughts are I am using the collectionGroup query incorrectly but I haven't found a solution for this yet. Should I even be using collectionGroup at all?? from what I've read, if I understand correctly this will query every ratedItem collection regardless of the user, which isn't what I want
const rateItem = async (itemId, liked) => {
try {
const itemRef = collection(db, 'users', currentUser.uid, 'ratedItems');
const q = query(
collectionGroup(db, 'users', currentUser.uid),
where('itemId', '==', itemId)
);
const querySnapshot = await getDocs(q);
if (querySnapshot.empty) {
await addDoc(itemRef, {
itemId: itemId,
timestamp: serverTimestamp(),
likedItem: liked,
});
} else {
await updateDoc(itemRef, {
timestamp: serverTimestamp(),
likedItem: liked,
});
}
} catch (err) {
console.log(err.message);
}
};
I assume the query is incorrect as if(querySnapshot.empty) always returns false even if there are no matching items (matching the itemId) in the ratedItems collection, so it always attempts to add a new item which results in duplicate entries in the collection.
You used the itemRef for both of addDoc and updateDoc which is not the proper way to do it. You need a correct query syntax in order to update your Firestore document.
if I force the code to bypass the conditional it throws an error when it attempts to update the existing item
You can try the code below to update your nested document:
const updateitemRef = query(
collection(db, 'users', 'user_item', 'ratedItems'),
where('itemId', '==', itemId)
);
const itemSnapshot = await getDocs(updateitemRef);
itemSnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
updateDoc(doc.ref, {
likedItem: liked,
timestamp: serverTimestamp()
});
});
For the complete code, you can try the code below:
const rateItem = async (itemId, liked) => {
try {
const q = query(
collectionGroup(db, 'users', currentUser.uid),
where('itemId', '==', itemId)
);
const querySnapshot = await getDocs(q);
const additemRef = collection(db, 'users', currentUser.uid, 'ratedItems');
const updateitemRef = query(
collection(db, 'users', currentUser.uid, 'ratedItems'),
where('itemId', '==', itemId)
);
const itemSnapshot = await getDocs(updateitemRef);
if (querySnapshot.empty) {
await addDoc(additemRef, {
itemId: itemId,
likedItem: liked,
timestamp: serverTimestamp()
});
} else {
itemSnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
updateDoc(doc.ref, {
likedItem: liked,
timestamp: serverTimestamp()
});
});
}
} catch (err) {
console.log(err.message);
}
};
For more references in creating a query, you can refer to the guides below:
Add a document
Perform simple and compound queries in Cloud Firestore
I'm trying do display data from Firestore database in my component.
This is my function:
const getData = async () => {
const data = [];
const querySnapshot = await getDocs(
collection(databaseRef, "mK7DFNJgRAPmtvgrZh7X6AOj8cR2")
);
console.log(querySnapshot);
querySnapshot.forEach((doc) => {
console.log(doc.id, " => ", doc.data().Title);
data.push({
About: doc.data().About,
Title: doc.data().Title,
Who: doc.data().Who,
});
});
setData(data);
};
Collection ID = Current logged in User.
I want to display every document.
Everything works fine but insteed of passing hard-coded string here:
collection(databaseRef, "mK7DFNJgRAPmtvgrZh7X6AOj8cR2")
I would like to pass variable where I store my UID.
Is there any way to do that?
Assuming your user is logged in, you should be able to access their UID via firebase.auth().currentUser.uid. This question's answers may be useful for more information on getting the current user's ID.
With that, you should be able to do:
const querySnapshot = await getDocs(
collection(databaseRef, firebase.auth().currentUser.uid)
);
to get the current user's documents.
https://firebase.google.com/docs/reference/js/v8/firebase.auth.Auth#currentuser
My console log is 2 differents id : sender.id and otherparticipants[0].id
I need to query my first document with sender.id OR otherParticipants (because it could be one or another one)
I'm trying to do that with an operator OR but firebase seems doesn't recognize my second value.
Do you know how I can have the same result in a good way?
.then(() => {
console.log('participant', otherParticipants[0].id, sender.id);
firebase
.firestore()
.collectionGroup('favoris')
.where('id', '==', sender.id || otherParticipants[0].id)
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log('data2', doc.data());
firebase
.firestore()
.collectionGroup('favoris')
.where('idUser', '==', sender.id || otherParticipants[0].id)
.get()
.then((querySnapshot) => {
console.log(querySnapshot.size);
querySnapshot.forEach((doc) => {
console.log('dataFinal', doc.data());
socialFeedsRef
.doc(sender.id)
.collection('chat_feed')
.doc(channel.id)
.set(
{
favoris: true,
},
{ merge: true },
);
});
});
});
});
});
That's not how you should create an OR query in Firestore:
.where('id', '==', sender.id || otherParticipants[0].id)
In this line, the || operator doesn't help.
You should create an array containing the IDs of the users who participate in the chat, say participantIDs: ["yourSenderUID", "yourOtherUid"].
Then, instead of the above call, add the following one:
.where("participantIDs", "array-contains-any", [sender.id, otherParticipants[0].id])
When you execute such a query, you'll get a warning message that sounds like this:
FAILED_PRECONDITION: The query requires a COLLECTION_GROUP_ASC index for collection favoris and field id. You can create it here: ...
Meaning that an index is required. You can simply click on that URL, or copy and paste the URL into a web browser and your index will be created automatically for you.
I need to update on document on my subcollection but I have an error:
Error: [firestore/not-found] Some requested document was not found.
First of all selected the good document on my collection Teams:
firestore()
.collection("Teams")
.where("tokenTeam", "==", "gvb2j3pcm9")
.get()
.then(async (querySnapshot) => {
if (querySnapshot.empty) {
console.log("no documents found");
} else {
querySnapshot.forEach(async (doc) => {
let Teams = doc._data;
console.log(Teams);
// code below fits in here
})
}
})
I have no error with the above code. Then I call my subcollection with just the statut in "attente" to select the one I want to update. My console.log(members) is working well.
After that I update the document selected I want to update which gives this error:
Error: [firestore/not-found] Some requested document was not found.
// insert into above code
doc.ref
.collection("membersList")
.where("statut", "==", "en attente")
.get()
.then((querySnapshot) => {
if (querySnapshot.empty) {
console.log("no documents found");
} else {
querySnapshot.forEach((doc) => {
let members = doc.id;
console.log(members);
doc.ref
.collection("membersList")
.doc(members)
.update({
statut: "Validé",
});
});
}
});
This is my data model:
Did I forget something?
The problem is in the query you are making inside the querySnapshot.forEach. The doc.ref is representing a reference to the current document you are operating in the foreach, which is already a memberList document.
So what you are doing currently in your code is looking for the same document as a separate document in a subcollection contained in your original document, which won't work, in order to work all you have to do is this:
doc.ref
.update({
statut: "Validé",
});
If I understand correctly, this is your goal: For the given team token/ID, update all members who have a "statut" value of "en attente" to "Validé".
As #RafaelLemos stated in their answer, you only need to use doc.ref instead of doc.ref.collection("membersList").doc(members). This mistake was caused by you shadowing the variable named doc and is why you should name your variables appropriately.
Similar to this answer, you can search for requests the same way. As you find each document to update, rather than update it immediately as you have in your code, you should make use of a batched write to make a single atomic database write.
firestore()
.collection("Teams")
.where("tokenTeam", "==", "gvb2j3pcm9")
.get()
.then(async (matchingTeamsQuerySnapshot) => {
if (matchingTeamsQuerySnapshot.empty) {
console.log("no teams found");
return;
}
// start a batched write
const batch = firestore().batch();
// for each team found, find members with "statut" of "en attente",
// and queue updating "statut" to "Validé"
await Promise.all(
matchingTeamsQuerySnapshot.docs
.map(async (teamDocSnapshot) => {
// const teamData = teamDocSnapshot.data();
// console.log(teamData);
const memberRequestsQuerySnapshot = await teamDocSnapshot.ref
.collection("membersList")
.where("statut", "==", "en attente")
.get();
memberRequestsQuerySnapshot.forEach(memberRequestDoc => {
batch.update(memberRequestDoc.ref, {
statut: "Validé"
});
});
})
);
// update the database all at once
return batch.commit();
})