have a cloud functions that run on call
the function utility is to remove an item from an array so to do so I'm doing an update on the fields that correspond to the doc id
(with firebase.firestore.FieldValue.arrayRemove(item)).
The problem is that all working fine it delete and update the state and the ui ,but its not deleting the last item (ui) and when i check in the firestore i see that the array is empty.
const remove_from_bucket = (my_id, item) => {
firebase
.firestore()
.collection("bucket")
.doc(my_id)
.update({
item_array: firebase.firestore.FieldValue.arrayRemove(item)
}).then((scc) => {
update_item_status_available(item)
console.log("success");
}).catch((err) => {
console.log(err.message);
});
};
Related
I am creating a clothing e-commerce application integrated with woocommerce and Firestore.
I currently am trying to build the 'add to wishlist part, here I am struggling with trying to update the items 'favourite' field in the database.
I present my Firestore"
my Firestore database
I have access to the item on my react native side
I need to be able to iterate through the objects, compare the nested object items ID against the idea of the item I am currently clicking on and change the favorite field to true.
Currently, I have tried to do the following, but to no avail.
const like = (item) => {
// db.collection("users").doc(user).collection("wishlist").doc(random).set({
// id:item.id,
// name:item.name,
// })
db.collection("users")
.doc(user)
.collection("products")
.doc("0")
.get()
.then((data) => {
const info = data.data();
});
};
In order to perform an update to an object that exists in an array-type field, you need to find that particular object first. Unfortunately, there is no way you can query a Firestore collection based on a value that exists in an object that is contained in an array. This kind of filtering cannot be achieved using partial data. To solve this, you have to read the array, find the desired elements that need to be updated, perform the update and then write the document back to Firestore.
I have also written an article called:
How to update an array of objects in Firestore?
so at the end I came up with a solution which I thought I would share here:
const like = (item) => {
const newData = { ...Data };
if (newData !== null) {
let index = newData.Products.findIndex((e) => {
return e.id === item.id;
});
console.log(index);
newData.Products[index].favourite = true;
db.collection("users")
.doc(userID)
.collection("products")
.doc("0")
.set(newData)
.then((data) => setData(data))
.catch((error) => console.log(error));
} else {
alert("An error has occured");
}
};
so this takes the data, saves it, adds the particular change and sets it again
so I have a problem right now. I'm entering the users dates into cloud firestore like this:
so this is a user collection, with a document by user's id's and then the dates are entered as a list. But whenever I refresh the page and enter new data, all the previous data disappears.
So I'm wondering how do I enter data so that it goes like collection(userCalendar).doc(USERID).collection(dates) and then it has all the user's data entered as strings rather than an array like I've been doing.
My code for the way it's behaving right now is below. Thank you! :)
export const allEvents = [];
const Calendar = () => {
const [date, setData] = useState([]);
const handleDateClick = async (DateClickArg) => {
if (DateClickArg.jsEvent.altKey) {
const title = prompt("Enter title", DateClickArg.dateStr); // allows user to put a title in
// making object
const event = {
title: title ? title : DateClickArg.dateStr,
start: DateClickArg.date,
allDay: true
}
allEvents.push(event)
const db = fire.firestore();
let currentUserUID = fire.auth().currentUser.uid
const doc = await fire
.firestore()
.collection("userCalendar")
.doc(currentUserUID)
.get()
db.collection("userCalendar")
.doc(currentUserUID)
.set({
activites: allEvents
})
}
}
You can use arrayUnion() to add new items to an array however it'll be difficult for you to query activities of a user.
For example, you cannot fetch a single activity from that array but you'll have to fetch all of them get the required one. Additionally, you cannot update an object in an array directly in Firestore.
Also a document has a max size limit of 1 MB so if a user can have many activities, it'll be best to create sub-collection.
I would recommend restructuring the following way:
users -> { userId } -> activities-> { activityId }
(col) (doc) (col) (doc)
All of user's activities/events are now in a sub-collection "activities" and each activity would be a document instead of an array item. With this you can easily read/update/delete a single activity.
Also checkout: Firestore subcollection vs array
Not sure whether this meets your requirement, but from my understanding you just want to update the activities with the allEvents which contains all the updated activities.
db.collection("userCalendar")
.doc(currentUserUID)
.set({
activites: allEvents
})
should become
db.collection("userCalendar")
.doc(currentUserUID)
.set({
activites: allEvents
}, { merge: true })
Or you can use the update method
db.collection("userCalendar")
.doc(currentUserUID)
.update({
activites: allEvents
})
From the docs
To update some fields of a document without overwriting the entire document, use the update() method:
import { doc, setDoc } from "firebase/firestore";
const cityRef = doc(db, 'cities', 'BJ');
setDoc(cityRef, { capital: true }, { merge: true });
It looks like you're overwriting your collection with every code execution:
db.collection("userCalendar")
.doc(currentUserUID)
.set({
activites: allEvents
})
You should consider to make an array union, so that the values are added to your collection instead of overwriting them:
db.collection("userCalendar")
.doc(currentUserUID)
.update({
activites: firebase.firestore.FieldValue.arrayUnion(
{
allEvents
}),
})
Also some examples from firestore docu:
https://cloud.google.com/firestore/docs/samples/firestore-data-set-array-operations
I am building a group collaboration application. I have ran into a problem on how to create groups which contain users in it, users are added to the group by their ids.
now the problem is how can a user who creates a group can write data across multiple users simultaneously . so that a group gets created in their database too, they can collaborate and write data on each others database.
it's like group chatting where users collaborate with each-other.
below code shows a user creating a group and trying to write the same group on his friends database, by using an array of user ids.
.doc([firebase.auth().currentUser.uid, newUser1, NewUser2])
firebase
.firestore()
.collection("Groups")
.doc([firebase.auth().currentUser.uid, newUser1, NewUser2])
.collection(AllGroups)
.add({
UpdatedOn: new Date().toString(),
CreatedOn: new Date().toString(),
CreatedBy:firebase.auth().currentUser.name,
users: [array of users]
tasks: [{ array of tasks }]
})
.then((sucess) => {
console.log("done");
})
.catch((err) => {
console.log(err);
});
but its not working please help me out, or please give me a better solution for it.
this is the redux call for calling the function
export const CreatingNewGroup = () => {
let user1id = "***********";
let user2id = "***********";
return async (dispatch) => {
firebase
.firestore()
.collection("Groups")
.doc([firebase.auth().currentUser.uid, user1id, user2id])
.collection("AllGroups")
.add({
UpdatedOn: new Date().toString(),
CreatedOn: new Date().toString(),
CreatedBy: firebase.auth().currentUser.email,
})
.then((sucess) => {
console.log("done");
})
.catch((err) => {
console.log(err);
});
};
};
function is called by this
export default function CreatGroups() {
const Dispatchs = useDispatch();
return (
<View>
<Button
title="Add"
onPress={() => Dispatchs(productsActions.CreatingNewGroup())}
/>
</View>
);
}
The error comes from here:
.doc([firebase.auth().currentUser.uid, newUser1, NewUser2])
The doc function expects a string here, not an array of strings. My guess is that it first tries to split the string on /, and the array you pass doesn't have a split operator.
If you want to write to multiple documents atomically, use a batch write operation.
This is a problem with either promises or finding a different way to solve the problem.
I have a user, that makes a document about their capabilities e.g.
price:
Bio:
called (contractorPage)
And i have users that look at these.
How do i make it so the users can save these by reference?
using firestore, can you make it so that you add these documents to a collection, but when he original document is changed these are also changed?
my first method is to save the Id of the contractorPage. Which is the user ID (UID) of the firebase auth of the person that made it.
Then To map through these to get all of the saved "id's" documents.
const [ idList, setIdList ] = useState([
])
const [ contractorList, setContractorList ] = useState([
])
useEffect(()=>{
/// IdList has the list of id's
//me.uid is the firebase auth user ID
firestore.collection("SavedId's").doc(me.uid).collection("id").get()
.then( async (querySnapshot) => {
await querySnapshot.forEach(doc => {
console.log(doc.id, " => ", doc.data());
setIdList([...idList, doc.data()]);
console.log("first",idList)
});
console.log("second",idList)
// contractorList has the list
idList.map((data, index) => (
firestore.collection("contractorPages").doc(data.id).get().then((word)=>{
console.log("hi", word.data())
if (word.exists) {
setContractorList([...contractorList, word.data()])
}
})
)
);
})
},[])
This does not work, because the idList.map() function runs before setIdList([...idList, doc.data()]); has finished.
How do I make sure the idList is set before I try to retrieve data from firestore with what is in it?
I use React with Redux and Firebase. Here is one of the functions from my Action.js
export const loadItemsInCategory = (categoryId) => {
return (dispatch) => {
let itemsArray = [];
firestoreService.getItemsInCategory(categoryId)
.then(updatedGroceryList => {
itemsArray = updatedGroceryList;
console.log(`category id is ${categoryId}`)
dispatch(loadItemsInCategoryHelper(categoryId, itemsArray))
})
.catch((error) => console.log(error));
}
}
It's a normal FireStore query. Here is what happens in firestoreService.getItemsInCategory(categoryId)
export const getItemsInCategory = async (categoryId) => {
console.log(`firebase category id is ${categoryId}`)
const snapshot = await db.collection('Item').where('category', '==', categoryId).get()
return snapshot.docs.map(doc => {console.log("called");return {id: doc.id, ...doc.data()}});
}
Right now, my application shows the list of items in the given Category. However, the list does not get updated when a new Item is added to the category by someone else. In other words, additions in FireStore collection does not reflect on my screen unless I refresh the page.
How can I code my webapp in such a way that any change on the FireStore end gets reflected on my webapp?
Thanks in advance!
Your code is doing a one-time query with get(). Queries made like this are not realtime. They don't refresh.
If you want to receive updates to your query in realtime, you should follow the documentation for realtime queries. Instead of using get(), you will use onSnapshot(). And instead of getting a promise, you will attach a listener callback that will be invoked whenever there is a change in the results of the query. Because of these differences, your code will look drastically different.