CollectionReference to DocumentReference - flutter

I'm trying to perform a firestore transaction in Flutter.
Therefore I need to pass the documentReference.
There is no problem, when accessing the "lesson" document based on the identifier.
The issue is when fetching the active user pass. The where I'm trying to use returns the Query, and the .reference() returns the CollectionReference (which is not accepted by the transaction method).
How can I get the reference to the document basing on the value of its field.
To spice it up: DB rules don't allow me to read ALL the passes. I've got only access to those, that have my UserID (double checked - working).
DocumentReference lessonRef =
await _db.collection('lessons').document(lesson.identifier);
CollectionReference passRef = await _db
.collection('passes')
.where('userID', isEqualTo: user.identifier).reference();

You can get the DocumentReference of the Queried documents like so:
Firestore.instance
.collection('passes')
.where('userID', isEqualTo: user.identifier)
.snapshots()
.listen((reference) =>
data.documents.forEach((doc) => /*do what you want with doc.reference*/));
(I'm not an expert in Flutter and I could't test the code, but I based the answer in the API reference)

Related

Why is vs code saying the method '.getDocuments' and the getter documents are not defined for types Query and QuerySnapshot respectively?

void _getQuestions() async {
// Query Firestore for questions with the specified tags
Query query = await _firestore
.collection('questions')
.where('tags', arrayContainsAny: widget.tags);
QuerySnapshot querySnapshot = await query.getDocuments();
setState(() {
_questions = querySnapshot.documents;
});
importing cloud_firestore.dart.
I expected the errors to leave, but they are still around.
The method to get the documents is called get() in Flutter, not getDocuments().
I recommend keeping the Firebase documentation handy for this sort of thing, for this case that'd be the section on getting multiple documents from a collection

Can't get one document from flutter cloud firestore

I'm trying to get one document by user id from firebase cloud firestore using flutter.
I tried firstly to fetch the data then added a condition to it, but i'm not able to display the data or even print it in the console!
Here is what i've tried so far:
database.dart:
Future<DocumentSnapshot?> getFileByUser(String userId) async {
return FirebaseFirestore.instance
.collection('cartesPro')
.where('cartUserId', isEqualTo: FirebaseAuth.instance.currentUser!.uid)
.get()
.then((value) {
value.docs.forEach((element) {
print(element.id);
});
});
}
ui page:
User? user = FirebaseAuth.instance.currentUser;
showFile() {
final files = DatabaseMethods().getFileByUser(user!.uid);
print(files);
}
and then made the call in a button so I can print the result only! it's returning the documents of the actual user, but I couldn't map the result in order to get the latest in timestamp order!
I appreciate any kind of help, thanks in advance!
If you want to get the most recent document for the user, you should order on the field that has the timestamp and the limit to a single result:
FirebaseFirestore.instance
.collection('cartesPro')
.where('cartUserId', isEqualTo: FirebaseAuth.instance.currentUser!.uid)
.orderBy('timestamp', descending: true)
.limit(1)
.get()
See the Firestore documentation on ordering and limiting data for more on this.

firestore security rules - create new user and check if name is free

to create a new user (via email authentication) I have to allow everything in firestore, is there a better way?
match /users/{userId=**} {
allow get, list;
}
Code:
I check whether the name is already taken
Future<bool> doesNameAlreadyExist(String name) async {
final QuerySnapshot result = await FirebaseFirestore.instance
.collection('users')
.where('name', isEqualTo: name)
.limit(1)
.get();
final List<DocumentSnapshot> documents = result.docs;
return documents.length == 1;
}
authentication then takes place later when the user presses the login button:
final auth = Provider.of(context)!.auth!;
String uid = await auth.createUserWithEmailAndPassword(
emailController.text,
passwordController.text,
nameController.text,
);
As mentioned in the Answer:
Enforcing uniqueness is only possible by creating an extra collection.
In your current structure, to know if a username is unique, you will
need to read each document. This is incredibly inefficient, and on top
of that it isn't possible in security rules, since they can only read
a few documents per rule.
The trick is to create an extra collection
of usernames, where you also have a document for each user, but now
the key/ID of each document is the username. With such a collection,
you can check for the existence of a certain document, which is a
primitive operation in the security rules.
For information you can check some similar scenarios - case_1 , case_2 and case_3.

how to delete document by field inside collection inside document inside collection on firestore

I have Doctor collection when each doctor (represent by his email ) has a collection called patients_waiting.
Now, what I'm trying to do is delete one document from the paitents_waiting collection by field calls patients containing his email.
but I tried many solutions and none of them works for me now.
what I have tried to do :
Firestore.instance
.collection("Doctors")
.document(doctorEmail)
.collection("paitents_waiting")
.document(paitentEmail)
.delete();
now it's not good because the document is saved in uid and not by email but I tried to play with the where function but with no success.
how do I found this document by email and delete him?
I will mention that I'm doing it on flutter, but I think it doesn't matter.
as long as you have the patient's email address you can search with and delete it
Firestore.instance
.collection("Doctors")
. document(doctorEmail)
.collection("paitents_waiting")
.where('patient', isEqualTo:paitentEmail )
.get().then((value) => value.docs.single.reference.delete())
Nb: you are using an old version of firestore
Inside your paitents_waiting collection, the documents are NOT named according to patient email, they are randomly generated Firebase IDs. Take a closer look.
Firestore.instance
.collection("Doctors")
.document(doctorEmail)
.collection("paitents_waiting")
.document(paitentEmail) //this in your Firebase isn't an email, it's "xaErf43Asd..etc"
.delete();
If you want to follow this approach, which should be working otherwise, when you want to create a patient waiting document, use .set instead of .add, and set the document id to your pateint's email, like this:
Firestore.instance
.collection("Doctors")
.document(doctorEmail)
.collection("paitents_waiting")
.document(paitentEmail)
.set({your patient data here});
This should get things working for you.
To delete all patients for a doctor by the email you can use a combination of Firestore query and batch updates. The first one we need to get all patients with the same email and the other to delete them. A function for that would look like this:
Future<void> deletePatiensForDoctor(String docEmail, String patEmail) async {
WriteBatch batch = FirebaseFirestore.instance.batch();
QuerySnapshot querySnapshot = await Firestore.instance
.collection("Doctors")
.document(docEmail)
.collection("paitents_waiting")
.where('email', isEqualTo: patEmail)
.get();
querySnapshot.docs.forEach((doc) {
batch.delete(doc.reference);
});
return batch.commit();
}

FLUTTER FIRESTORE -Query the field and get document id and check other field

am trying to get the searched value(userid) which is in the field of a document in firestore I want to check the other fields(status) of the document I tried this method but failed
handlesubmit(BuildContext context)async{
final QuerySnapshot searcheduserid=
await Firestore.instance.collection('users')
.where('userid',isEqualTo: userid).limit(1).getDocuments();
final userdocid=searcheduserid.documents.map((doc)=>doc.documentID);
final DocumentSnapshot getuserdoc= await Firestore.instance.collection('users')
.document(userdocid).get();
final userstatus = getuserdoc.data['status'];
// I GET AN ERROR HERE ERROR SAYS
// METHOD [](status) was called on null
if(userstatus==null){
return showdialog( context,'the entered user id status does not exist');
}
}
You probably copied an older version of your code because it is unlikely that your code compiles the following line of your program:
final DocumentSnapshot getuserdoc= await Firestore
.instance
.collection('users')
.document(userdocid).get();
The error message on my system is:
The argument type 'Iterable<String>' can't be assigned to the parameter type 'String'.
Which means that userdocid is an Iterable of type String (Iterable<String>), but a parameter which is of type String is expected.
You have multiple options of fixing the problem, but I suggest the following:
Since you are only expecting one document from your QuerySnapshot it is enough to just look at the first document.
final QuerySnapshot searchedUserId = await Firestore.instance
.collection('users')
.where('userid', isEqualTo: userid)
.limit(1)
.getDocuments();
// if it is possible that searchedUserId returns no document make sure to
// check whether searchedUserId.documents.length > 0,
// otherwise searchedUserId.documents.first will throw an error
DocumentSnapshot document = searchedUserId.documents.first;
final userDocId = document.documentID;
final DocumentSnapshot getuserdoc =
await Firestore.instance.collection('users').document(userDocId).get();
Improved Solution:
However I think your code is a bit redundant anyways, because you are looking up a field of a document which has the same value as the document ID. You could shorten the whole code to
final DocumentSnapshot getuserdoc =
await Firestore.instance.collection('users').document(userid).get();
Error calling getuserdoc.data['status']
If you get an error saying something similar to
[](status) was called on null
Then that means getuserdoc has no value. This is likely due to the fact that there is no such database entry with the given ID. Check if the ID is in your database, otherwise comment below for additional information, because the provided code had compilation errors and does not run at all.