I have a subcollection 'favourites' under my 'users' collection and I would like to delete any of its documents by checking that the field 'prod_id' is isEqualTo prodId
THis is how I create the subcollection & document when a user taps the favourite button:
_usersCollectionReference
.doc(userId)
.collection('favourites')
.add({'prod_id': prodId});
Now, I want to be able to delete this document
To delete any document you must know it's ID or have a DocumentReference to it. For that you just need to know the userId and fetch documents where prod_id is equal to the product IDs you want to delete.
FirebaseFirestore.instance
.collection('users')
.doc(userId)
.collection('favourites')
.where('prod_id', whereIn: [...])
.get()
.then((snapshot) {
// ...
});
snapshots is a QuerySnapshot and has a property docs which is an array of QueryDocumentSnapshot. You can loop through that array and delete each document by accessing their reference.
For example, deleting first document in that would be:
snapshot.docs[0].reference.delete()
You can also do a check on the collection itself with where logic
const snapshot = await contentRef.where('favouritething','==', favoriteId)
.get().then((querySnapshot)=>{
// return query snapshot
return querySnapshot.docs
// .map(doc => doc.data());
})
you can do this very easily and return a result
let contentArray: any[] = []
// call the content collection
const contentRef = db.collection('favourites');
// snapshot data on get
const snapshot = await contentRef.get().then((querySnapshot)=>{
// return query snapshot
return querySnapshot.docs
// .map(doc => doc.data());
})
// this statement can be joined to the other
// loop through each snapshot as document
snapshot.forEach((doc)=>{
// create new constant as document of each loop
const newdoc = doc.data()
// push new constant to content array
if(newdoc.YOURTHING==='your thing you want to look for'){
const deleteDocId=newdoc?.id
db.collection('favourites').doc(`${deleteDocId}`).delete().then((result)=>{
return result
})
}
})
})
You can read about why and how here:
https://firebase.google.com/docs/firestore/manage-data/delete-data
Related
I am trying to update a field in the last document in the Firestore collection. My updating method is below:
updateHours() {
return usersRef.doc(firebaseAuth.currentUser!.uid).collection('posts')
.orderBy('datePublished', descending: true)
.limit(1).get().then((querySnapshot) {
return querySnapshot.docs.map((e) {
usersRef
.doc(firebaseAuth.currentUser!.uid).collection('posts')
.doc(e.reference.id)
.update({"totalTime": FieldValue.increment(1)});
});
});
}
This does not work. If I use .forEach(), then all documents get updated. So, how to update only the last document field?
To be able to update the totalTime field inside the last document, please use the following lines of code:
void updateHours() async{
CollectionReference postsRef = usersRef
.doc(firebaseAuth.currentUser!.uid)
.collection('posts');
QuerySnapshot query = await postsRef.orderBy('datePublished', descending: true)
.limit(1)
.getDocuments();
query.documents.forEach((doc) {
doc.reference.updateData({"totalTime": FieldValue.increment(1)});
});
}
Don't forget that Firebase APIs are asynchronous, and you need to wait for the data until it becomes available.
I have create document like this in react native, I am using rnfirebase library
firestore()
.collection('WaterCanData')
.doc(EntryDate)
.collection('Entries')
.doc(values.customerName)
.set({
CustomerName: values.customerName,
CansOut: values.cansOut,
JarsOut: values.jarsOut,
EmptyCansIn: values.emptyCansIn,
JarsIn: values.jarsIn,
Bottles: values.bottles,
Ice: values.ice
})
.then(() => {
console.log('Entry added!!!!!!!!!');
})
When I try to retrieve EntryDate from WaterCanData Coellection I am not able to fetch it(Document name appears in italic font), So how should I retrive this document which contains a subcollection, Below I have attached my ss of data structure
Data structure
Data structuree
The reason your document appears in italics is because it doesn't currently exist. In Cloud Firestore, subcollections can exist without requiring their parent document to also exist.
Non-existant documents will not appear in queries or snapshots in the client SDKs as stated in the Firebase Console.
This document does not exist, it will not appear in queries or snapshots
If you want to be able to get your entry dates, you need to create the document (which can be empty).
firebase.firestore()
.collection('WaterCanData')
.doc(EntryDate)
.set({}); // an empty document
To create the document at the same time as an entry on it's subcollection, you can use a batched write like so:
const db = firebase.firestore();
const batch = db.batch();
// get references to the relevant locations
const entryDateRef = db
.collection('WaterCanData')
.doc(EntryDate);
const customerRef = entryDateRef
.collection('Entries')
.doc(values.customerName);
// queue the data to write
batch.set(entryDateRef, {});
batch.set(customerRef, {
CustomerName: values.customerName,
CansOut: values.cansOut,
JarsOut: values.jarsOut,
EmptyCansIn: values.emptyCansIn,
JarsIn: values.jarsIn,
Bottles: values.bottles,
Ice: values.ice
})
// make changes to database
batch.commit()
.then(() => {
console.log('Entry added!!!!!!!!!');
});
This will then allow you to list all of the entry dates in your database using something like:
firebase.firestore().collection('WaterCanData')
.get()
.then((querySnapshot) => {
querySnapshot.forEach(doc => {
const entryDate = doc.id;
// const customerEntriesRef = doc.ref.collection('Entries');
console.log('Entry date found: ' + entryDate);
}
});
If (as an example) you wanted to also find how many entries were linked to a given date, you would need to also query each subcollection (here the code gets a little more confusing).
firebase.firestore().collection('WaterCanData')
.get()
.then((querySnapshot) => {
const fetchSizePromises = [];
// for each entry date, get the size of it's "Entries" subcollection
querySnapshot.forEach(doc => {
const entryDate = doc.id;
const customerEntriesRef = doc.ref.collection('Entries');
// if this get() fails, just store the error rather than throw it.
const thisEntrySizePromise = customerEntriesRef.get()
.then(
(entriesQuerySnapshot) => {
return { date: entryDate, size: entriesQuerySnapshot.size }
},
(error) => {
return { date: entryDate, size: -1, error }
}
);
// add this promise to the queue
fetchSizePromises.push(thisEntrySizePromise)
}
// wait for all fetch operations and return their results
return Promise.all(fetchSizePromises);
})
.then((entryInfoResults) => {
// for each entry, log the result
entryInfoResults.forEach((entryInfo) => {
if (entryInfo.error) {
// this entry failed
console.log(`${entryInfo.date} has an unknown number of customers in its Entries subcollection due to an error`, entryInfo.error);
} else {
// got size successfully
console.log(`${entryInfo.date} has ${entryInfo.size} customers in its Entries subcollection`);
}
}
});
Using below code you can console every document id inside waterCanData collection. In your database you have only one document, then it will console your document id. (10042021)
firestore()
.collection('WaterCanData')
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(doc.id)
});
})
I have a document, and inside of it there is a collection called relatives. In cloud functions, I have onUpdate() listener for this document. Once something is changed, I want to access that collection inside of my document. Also documents in the collection relatives.
Here is how it looks like:
What I have tried
exports.UpdateLocations = functions.firestore.document("users/{userID}").onUpdate((change, context) => {
const userEmail = change.after.data().email;
const prevLocation = change.before.data().userLocation;
const currentLocation = change.after.data().userLocation;
if (prevLocation === currentLocation) return 0;
if (change.after.data().userType.toString() === "Patient") {
const userLocation = change.after.data().userLocation;
const relatives = change.after.data().relatives;
console.log("User's Current Location: " + userLocation);
console.log("Relatives : "+relatives );
}
return;
});
I want to access relatives and its documents. So I can search and compare field and update them on purpose.
To get a subcollection from a DocumentSnapshot, you must first get a DocumentReference to the document for that snapshot, and then find the CollectionReference under that.
In code:
change.after.ref.collection("relatives")
In here:
change.after gives you the DocumentSnapshot of the modified document.
change.after.ref then gives you the DocumentReference of that document, so its location in the database.
change.after.ref.collection("relatives") then gives you the CollectionReference to the relatives subcollection of the document.
So get data from these subcollections you'll have to actually load that data, it is not already included in the change object that is passed to your function.
So if you want to load all relatives for the user that triggered the function, it'd be something like:
let relativesRef = change.after.ref.collection("relatives");
return relatives.get().then((querySnapshot) => {
querySnapshot.forEach((relativeDoc) => {
console.log(doc.id, doc.data().relativeaccount);
});
});
I have a list that contains the document Ids of a particular collection "users", and I want to get documents only present in this list, and these documents are in "users" collection as mention before.
Code:
getUsers() async
{
double radius = 0.3;
String field = "GeoPosition";
print(currentUser.point.longitude);
GeoFirePoint center = geo.point(latitude: currentUser.point.latitude, longitude: currentUser.point.longitude);
var collectionRef = Firestore.instance.collection('user_locations').document(currentUser.pincode) .collection('Users_complete_address_and_geopoint');
this.stream = geo.collection(collectionRef: collectionRef).within(center: center, radius: radius, field: field, strictMode: false);
Future<List<certainrangeusers>> users1 = stream.first.then(
(documents) => documents.map((doc) => certainrangeusers(
id: doc['userPhone'],
)
).toList());
users1.then((val) async{
QuerySnapshot snapshot = await Firestore.instance.collection('users').where('id', isEqualTo: val.first.id).getDocuments();
List<User> users = snapshot.documents.map((doc) => User.fromDocument(doc)).toList();
setState(() {
this.users = users;
});
});
}
Firebase Structure:
Click here for the firebase structure
Code In image format:
Click here for the image
In orange box, "users1" is a list having document IDs...of users 10km users
In the pink box, we r using the value of the list...
In the green box, we need to pass the document ids present in the above list...
P.s: I am using "val.first.id" just to bring the document present at first in the list........But I need to bring every document present in that list...so that's a point I have struck...
Here how to search for all documents from the list id
instead of:
await Firestore.instance.collection('users').where('id', isEqualTo:
val.first.id).getDocuments();
use this:
await Firestore.instance.collection('users').where('id', whereIn:
val).getDocuments();
Since you have a list of certainchangeuser, do this to get the ids.
users1.then((val){
// Get the ids
List ids = [];
for (var value in val){
ids.add(value.id);
}
//Then
QuerySnapshot = await
Firestore.instance.collection('users').where('id',
whereIn:ids).getDocuments();
....
});
You can use a transaction for this purpose. Firestore transactions
I want to update a document field and I've tried the following code but it doesn't update.
can anyone give me a solution, please?
My Code:
var snapshots = _firestore
.collection('profile')
.document(currentUserID)
.collection('posts')
.snapshots();
await snapshots.forEach((snapshot) async {
List<DocumentSnapshot> documents = snapshot.documents;
for (var document in documents) {
await document.data.update(
'writer',
(name) {
name = this.name;
return name;
},
);
print(document.data['writer']);
//it prints the updated data here but when i look to firebase database
//nothing updates !
}
});
For cases like this, I always recommend following the exact types in the documentation, to see what options are available. For example, a DocumentSnapshot object's data property is a Map<String, dynamic>. To when you call update() on that, you're just updating an in-memory representation of the document, and not actually updating the data in the database.
To update the document in the database, you need to call the DocumentReference.updateData method. And to get from the DocumentSnapshot to a DocumentReference, you call the DocumentSnapshot.reference property.
So something like:
document.reference.updateData(<String, dynamic>{
name: this.name
});
Unrelated to this, your code looks a bit non-idiomatic. I'd recommend using getDocuments instead of snapshots(), as the latter will likely result in an endless loop.
var snapshots = _firestore
.collection('profile')
.document(currentUserID)
.collection('posts')
.getDocuments();
await snapshots.forEach((document) async {
document.reference.updateData(<String, dynamic>{
name: this.name
});
})
The difference here is that getDocuments() reads the data once, and returns it, while snapshots() will start observing the documents, and pass them to us whenever there's a change (including when you update the name).
Update 2021:
Lot of things have changed in the API, for example, Firestore is replaced by FirebaseFirestore, doc is in, etc.
Update a document
var collection = FirebaseFirestore.instance.collection('collection');
collection
.doc('some_id') // <-- Doc ID where data should be updated.
.update({'key' : 'value'}) // <-- Updated data
.then((_) => print('Updated'))
.catchError((error) => print('Update failed: $error'));
Update nested value in a document:
var collection = FirebaseFirestore.instance.collection('collection');
collection
.doc('some_id') // <-- Doc ID where data should be updated.
.update({'key.foo.bar' : 'nested_value'}) // <-- Nested value
.then((_) => print('Updated'))
.catchError((error) => print('Update failed: $error'));
To update some fields of a document without overwriting the entire document, use the following language-specific update() methods:
final washingtonRef = FirebaseFirestore.instance.collection("cites").doc("DC");
washingtonRef.update({"capital": true}).then(
(value) => print("DocumentSnapshot successfully updated!"),
onError: (e) => print("Error updating document $e"));
Server Timestamp
You can set a field in your document to a server timestamp which tracks when the server receives the update.
final docRef = FirebaseFirestore.instance.collection("objects").doc("some-id");
final updates = <String, dynamic>{
"timestamp": FieldValue.serverTimestamp(),
};
docRef.update(updates).then(
(value) => print("DocumentSnapshot successfully updated!"),
onError: (e) => print("Error updating document $e"));
Update fields in nested objects
If your document contains nested objects, you can use "dot notation" to reference nested fields within the document when you call update():
// Assume the document contains:
// {
// name: "Frank",
// favorites: { food: "Pizza", color: "Blue", subject: "recess" }
// age: 12
// }
FirebaseFirestore.instance
.collection("users")
.doc("frank")
.update({"age": 13, "favorites.color": "Red"});
Update elements in an array
If your document contains an array field, you can use arrayUnion() and arrayRemove() to add and remove elements. arrayUnion() adds elements to an array but only elements not already present. arrayRemove() removes all instances of each given element.
final washingtonRef = FirebaseFirestore.instance.collection("cities").doc("DC");
// Atomically add a new region to the "regions" array field.
washingtonRef.update({
"regions": FieldValue.arrayUnion(["greater_virginia"]),
});
// Atomically remove a region from the "regions" array field.
washingtonRef.update({
"regions": FieldValue.arrayRemove(["east_coast"]),
});
Increment a numeric value
You can increment or decrement a numeric field value as shown in the following example. An increment operation increases or decreases the current value of a field by the given amount.
var washingtonRef = FirebaseFirestore.instance.collection('cities').doc('DC');
// Atomically increment the population of the city by 50.
washingtonRef.update(
{"population": FieldValue.increment(50)},
);