Flutterfire how can i fetch data inside of unique id doc()? - firebase

i trying to get a string/check a string for a validation in my flutter app. i've been trying to use the .where() function but they gave me this error when i did it
The argument type 'Future<QuerySnapshot<Object?>>' can't be assigned to the parameter type 'Future<DocumentSnapshot<Object?>>?'
this is the code that give me the error
final phoneNumber = ModalRoute.of(context)!.settings.arguments as String;
CollectionReference users = FirebaseFirestore.instance.collection('users');
return FutureBuilder<DocumentSnapshot>(
future: users.where("phoneNumber", isEqualTo : phoneNumber).get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return const Text("Something went wrong");
}
if (snapshot == null || !snapshot.data!.exists) {
return const Text("data doesn't exist");
}
if (snapshot.hasData) {
return const Text("data exist already");
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data =
snapshot.data!.data() as Map<String, dynamic>;
return Text("Full Name: ${data['full_name']} ${data['last_name']}");
}
return const Text("loading");
},
);
been trying and searching for 3-4 hours but all the reference tell me that i need to input the unique id
that will look like this
final docSnapshot = await Firestore.instance
.collection("$Friseur/1/$Tag/1/$Uhrzeit")
.document(${doc_id_here})
.get();
if(docSnapshot.exists) {
setState(...)
}
else {
setState(...)
}

Change FutureBuilder<DocumentSnapshot> to FutureBuilder<QuerySnapshot>
when you use where operation it return the QuerySnapshot.

Add doc function with document id after where function because future parameter accept Future<DocumentSnapshot<Object?>>?
future: users.where("phoneNumber", isEqualTo : phoneNumber).doc(documentId).get(),

Related

Getting One-Time Read Data From Nested Firestore in Flutter

I'm currently trying to make an app that need to read data just for one time from a nested Firestore Database.
Here's my currently working code
FirebaseFirestore firestore = FirebaseFirestore.instance;
CollectionReference users = firestore.collection('users');
FirebaseAuth _auth = FirebaseAuth.instance;
FutureBuilder getTheData = FutureBuilder<DocumentSnapshot>(
future: users.doc(_auth.currentUser!.uid).get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError || (snapshot.hasData && !snapshot.data!.exists)) {
return Text("Something went wrong");
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data =
snapshot.data!.data() as Map<String, dynamic>;
String _condition = data['condition'];
String _descCondition = data['descCondition'];
int _percentageValue = data['percentageValue'];
return defaultDraw(
condition: _condition,
descCondition: _descCondition,
percentageValue: _percentageValue,
);
}
return defaultDraw(
condition: "Loading",
descCondition: "",
percentageValue: 0,
);
},
);
and it's able to read this data (condition, descCondition, and percentageValue) :
but when I'm trying to read this data :
Which is another collection inside of the previous document (a collection named 'adviceData' with random document ID that I'm trying to read), I'm getting an error like this :
Here's my code :
FirebaseFirestore firestore = FirebaseFirestore.instance;
CollectionReference users = firestore.collection('users');
FirebaseAuth _auth = FirebaseAuth.instance;
FutureBuilder _getParameterData = FutureBuilder<DocumentSnapshot>(
future: users
.doc(_auth.currentUser!.uid)
.collection('adviceData')
.doc()
.get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError || (snapshot.hasData && !snapshot.data!.exists)) {
return Text("Something went wrong");
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data =
snapshot.data!.data() as Map<String, dynamic>;
String _advicePhLow = data['advicePhLow'];
String _advicePhHigh = data['advicePhHigh'];
String _adviceTempLow = data['adviceTempLow'];
String _adviceTempHigh = data['adviceTempHigh'];
String _adviceHeightLow = data['adviceHeightLow'];
String _adviceHeightHigh = data['adviceHeightHigh'];
return drawParameter(
advicePhLow: _advicePhLow,
adviceTempLow: _adviceTempLow,
adviceHeightLow: _adviceHeightLow,
);
}
return drawParameter();
},
);
and my question is :
Where did I make mistakes?
Is there any better method to get a data from firestore?
Thanks in advance
If you want to get all documents from the subcollection adviceData you would need to get a QuerySnapshot like here:
FutureBuilder<QuerySnapshot>(
future: users
.doc(_auth.currentUser!.uid)
.collection('adviceData')
.get(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return ListView(
children: snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data = document.data()! as Map<String, dynamic>;
return ListTile(
title: Text(data['full_name']),
subtitle: Text(data['company']),
);
}).toList(),
);
},
);
}
If you want to get a single document from that subcollection you would need to define the id of that specific document:
FutureBuilder _getParameterData = FutureBuilder<DocumentSnapshot>(
future: users
.doc(_auth.currentUser!.uid)
.collection('adviceData')
.doc('documentID') // here
.get(),
builder:
You can find more about both methods here.

How can i get data from firebase by document ID in Flutter? [duplicate]

Edit: This Question is outdated, and I am sure, new documentation and more recent answers are available as of now.
I want to retrieve data of only a single document via its ID. My approach with example data of:
TESTID1 {
'name': 'example',
'data': 'sample data',
}
was something like this:
Firestore.instance.document('TESTID1').get() => then(function(document) {
print(document('name'));
}
but that does not seem to be correct syntax.
I was not able to find any detailed documentation on querying firestore within flutter (dart) since the firebase documentation only addresses Native WEB, iOS, Android etc. but not Flutter. The documentation of cloud_firestore is also way too short. There is only one example that shows how to query multiple documents into a stream which is not what i want to do.
Related issue on missing documentation:
https://github.com/flutter/flutter/issues/14324
It can't be that hard to get data from a single document.
UPDATE:
Firestore.instance.collection('COLLECTION').document('ID')
.get().then((DocumentSnapshot) =>
print(DocumentSnapshot.data['key'].toString());
);
is not executed.
but that does not seem to be correct syntax.
It is not the correct syntax because you are missing a collection() call. You cannot call document() directly on your Firestore.instance. To solve this, you should use something like this:
var document = await Firestore.instance.collection('COLLECTION_NAME').document('TESTID1');
document.get() => then(function(document) {
print(document("name"));
});
Or in more simpler way:
var document = await Firestore.instance.document('COLLECTION_NAME/TESTID1');
document.get() => then(function(document) {
print(document("name"));
});
If you want to get data in realtime, please use the following code:
Widget build(BuildContext context) {
return new StreamBuilder(
stream: Firestore.instance.collection('COLLECTION_NAME').document('TESTID1').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return new Text("Loading");
}
var userDocument = snapshot.data;
return new Text(userDocument["name"]);
}
);
}
It will help you set also the name to a text view.
Null safe code (Recommended)
You can either query the document in a function (for example on press of a button) or inside a widget (like a FutureBuilder).
In a method: (one time listen)
var collection = FirebaseFirestore.instance.collection('users');
var docSnapshot = await collection.doc('doc_id').get();
if (docSnapshot.exists) {
Map<String, dynamic>? data = docSnapshot.data();
var value = data?['some_field']; // <-- The value you want to retrieve.
// Call setState if needed.
}
In a FutureBuilder (one time listen)
FutureBuilder<DocumentSnapshot<Map<String, dynamic>>>(
future: collection.doc('doc_id').get(),
builder: (_, snapshot) {
if (snapshot.hasError) return Text ('Error = ${snapshot.error}');
if (snapshot.hasData) {
var data = snapshot.data!.data();
var value = data!['some_field']; // <-- Your value
return Text('Value = $value');
}
return Center(child: CircularProgressIndicator());
},
)
In a StreamBuilder: (always listening)
StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: collection.doc('doc_id').snapshots(),
builder: (_, snapshot) {
if (snapshot.hasError) return Text('Error = ${snapshot.error}');
if (snapshot.hasData) {
var output = snapshot.data!.data();
var value = output!['some_field']; // <-- Your value
return Text('Value = $value');
}
return Center(child: CircularProgressIndicator());
},
)
If you want to use a where clause
await Firestore.instance.collection('collection_name').where(
FieldPath.documentId,
isEqualTo: "some_id"
).getDocuments().then((event) {
if (event.documents.isNotEmpty) {
Map<String, dynamic> documentData = event.documents.single.data; //if it is a single document
}
}).catchError((e) => print("error fetching data: $e"));
This is simple you can use a DOCUMENT SNAPSHOT
DocumentSnapshot variable = await Firestore.instance.collection('COLLECTION NAME').document('DOCUMENT ID').get();
You can access its data using variable.data['FEILD_NAME']
Update FirebaseFirestore 12/2021
StreamBuilder(
stream: FirebaseFirestore.instance
.collection('YOUR COLLECTION NAME')
.doc(id) //ID OF DOCUMENT
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return new CircularProgressIndicator();
}
var document = snapshot.data;
return new Text(document["name"]);
}
);
}
This is what worked for me in 2021
var userPhotos;
Future<void> getPhoto(id) async {
//query the user photo
await FirebaseFirestore.instance.collection("users").doc(id).snapshots().listen((event) {
setState(() {
userPhotos = event.get("photoUrl");
print(userPhotos);
});
});
}
Use this code when you just want to fetch a document from firestore collection , to perform some operations on it, and not to display it using some widget (updated jan 2022 )
fetchDoc() async {
// enter here the path , from where you want to fetch the doc
DocumentSnapshot pathData = await FirebaseFirestore.instance
.collection('ProfileData')
.doc(currentUser.uid)
.get();
if (pathData.exists) {
Map<String, dynamic>? fetchDoc = pathData.data() as Map<String, dynamic>?;
//Now use fetchDoc?['KEY_names'], to access the data from firestore, to perform operations , for eg
controllerName.text = fetchDoc?['userName']
// setState(() {}); // use only if needed
}
}
Simple way :
StreamBuilder(
stream: FirebaseFirestore.instance
.collection('YOUR COLLECTION NAME')
.doc(id) //ID OF DOCUMENT
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return new CircularProgressIndicator();
}
var document = snapshot.data;
return new Text(document["name"]);
}
);
}
var document = await FirebaseFirestore.instance.collection('Users').doc('CXvGTxT49NUoKi9gRt96ltvljz42').get();
Map<String,dynamic>? value = document.data();
print(value!['userId']);
You can get the Firestore document by following code:
future FirebaseDocument() async{
var variable = await FirebaseFirestore.instance.collection('Collection_name').doc('Document_Id').get();
print(variable['field_name']);
}
Use this simple code:
Firestore.instance.collection("users").document().setData({
"name":"Majeed Ahmed"
});

How can I put retrieved data from firebase to a widget in Flutter?

final String uid;
final firestoreInstance = Firestore.instance;
void printData() async{
var firebaseUser = await FirebaseAuth.instance.currentUser();
firestoreInstance.collection("users").document(firebaseUser.uid).get().then((value){
print(value.data);
});
}
So this function prints to console the retrieved data from firebase firestore when I press the button. But I want to put them into a widget and display them in my app. For ex: Text(printData()) - but it's not allowed. How can I do that?
You need to use a FutureBuilder to display data that you are getting asynchronously, therefore create a method that returns a Future:
Future<DocumentSnapshot> getDocument() async{
var firebaseUser = await FirebaseAuth.instance.currentUser();
return Firestore.instance.collection("users").document(firebaseUser.uid).get();
}
Then in the FutureBuilder assign the method to the property future:
body: Container(
padding: EdgeInsets.all(10.0),
child: FutureBuilder(
future: getDocument(),
builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Text(snapshot.data["name"].toString());
} else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data");
}
return CircularProgressIndicator();
},
),
Assuming you have the following db:
Collection ("users") ----> Document (userId) ---> fields name : your_name
Read more about future:
https://api.dart.dev/stable/2.9.1/dart-async/Future-class.html
https://dart.dev/codelabs/async-await
https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html

Query a single document from Firestore in Flutter (cloud_firestore Plugin)

Edit: This Question is outdated, and I am sure, new documentation and more recent answers are available as of now.
I want to retrieve data of only a single document via its ID. My approach with example data of:
TESTID1 {
'name': 'example',
'data': 'sample data',
}
was something like this:
Firestore.instance.document('TESTID1').get() => then(function(document) {
print(document('name'));
}
but that does not seem to be correct syntax.
I was not able to find any detailed documentation on querying firestore within flutter (dart) since the firebase documentation only addresses Native WEB, iOS, Android etc. but not Flutter. The documentation of cloud_firestore is also way too short. There is only one example that shows how to query multiple documents into a stream which is not what i want to do.
Related issue on missing documentation:
https://github.com/flutter/flutter/issues/14324
It can't be that hard to get data from a single document.
UPDATE:
Firestore.instance.collection('COLLECTION').document('ID')
.get().then((DocumentSnapshot) =>
print(DocumentSnapshot.data['key'].toString());
);
is not executed.
but that does not seem to be correct syntax.
It is not the correct syntax because you are missing a collection() call. You cannot call document() directly on your Firestore.instance. To solve this, you should use something like this:
var document = await Firestore.instance.collection('COLLECTION_NAME').document('TESTID1');
document.get() => then(function(document) {
print(document("name"));
});
Or in more simpler way:
var document = await Firestore.instance.document('COLLECTION_NAME/TESTID1');
document.get() => then(function(document) {
print(document("name"));
});
If you want to get data in realtime, please use the following code:
Widget build(BuildContext context) {
return new StreamBuilder(
stream: Firestore.instance.collection('COLLECTION_NAME').document('TESTID1').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return new Text("Loading");
}
var userDocument = snapshot.data;
return new Text(userDocument["name"]);
}
);
}
It will help you set also the name to a text view.
Null safe code (Recommended)
You can either query the document in a function (for example on press of a button) or inside a widget (like a FutureBuilder).
In a method: (one time listen)
var collection = FirebaseFirestore.instance.collection('users');
var docSnapshot = await collection.doc('doc_id').get();
if (docSnapshot.exists) {
Map<String, dynamic>? data = docSnapshot.data();
var value = data?['some_field']; // <-- The value you want to retrieve.
// Call setState if needed.
}
In a FutureBuilder (one time listen)
FutureBuilder<DocumentSnapshot<Map<String, dynamic>>>(
future: collection.doc('doc_id').get(),
builder: (_, snapshot) {
if (snapshot.hasError) return Text ('Error = ${snapshot.error}');
if (snapshot.hasData) {
var data = snapshot.data!.data();
var value = data!['some_field']; // <-- Your value
return Text('Value = $value');
}
return Center(child: CircularProgressIndicator());
},
)
In a StreamBuilder: (always listening)
StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: collection.doc('doc_id').snapshots(),
builder: (_, snapshot) {
if (snapshot.hasError) return Text('Error = ${snapshot.error}');
if (snapshot.hasData) {
var output = snapshot.data!.data();
var value = output!['some_field']; // <-- Your value
return Text('Value = $value');
}
return Center(child: CircularProgressIndicator());
},
)
If you want to use a where clause
await Firestore.instance.collection('collection_name').where(
FieldPath.documentId,
isEqualTo: "some_id"
).getDocuments().then((event) {
if (event.documents.isNotEmpty) {
Map<String, dynamic> documentData = event.documents.single.data; //if it is a single document
}
}).catchError((e) => print("error fetching data: $e"));
This is simple you can use a DOCUMENT SNAPSHOT
DocumentSnapshot variable = await Firestore.instance.collection('COLLECTION NAME').document('DOCUMENT ID').get();
You can access its data using variable.data['FEILD_NAME']
Update FirebaseFirestore 12/2021
StreamBuilder(
stream: FirebaseFirestore.instance
.collection('YOUR COLLECTION NAME')
.doc(id) //ID OF DOCUMENT
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return new CircularProgressIndicator();
}
var document = snapshot.data;
return new Text(document["name"]);
}
);
}
This is what worked for me in 2021
var userPhotos;
Future<void> getPhoto(id) async {
//query the user photo
await FirebaseFirestore.instance.collection("users").doc(id).snapshots().listen((event) {
setState(() {
userPhotos = event.get("photoUrl");
print(userPhotos);
});
});
}
Use this code when you just want to fetch a document from firestore collection , to perform some operations on it, and not to display it using some widget (updated jan 2022 )
fetchDoc() async {
// enter here the path , from where you want to fetch the doc
DocumentSnapshot pathData = await FirebaseFirestore.instance
.collection('ProfileData')
.doc(currentUser.uid)
.get();
if (pathData.exists) {
Map<String, dynamic>? fetchDoc = pathData.data() as Map<String, dynamic>?;
//Now use fetchDoc?['KEY_names'], to access the data from firestore, to perform operations , for eg
controllerName.text = fetchDoc?['userName']
// setState(() {}); // use only if needed
}
}
Simple way :
StreamBuilder(
stream: FirebaseFirestore.instance
.collection('YOUR COLLECTION NAME')
.doc(id) //ID OF DOCUMENT
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return new CircularProgressIndicator();
}
var document = snapshot.data;
return new Text(document["name"]);
}
);
}
var document = await FirebaseFirestore.instance.collection('Users').doc('CXvGTxT49NUoKi9gRt96ltvljz42').get();
Map<String,dynamic>? value = document.data();
print(value!['userId']);
You can get the Firestore document by following code:
future FirebaseDocument() async{
var variable = await FirebaseFirestore.instance.collection('Collection_name').doc('Document_Id').get();
print(variable['field_name']);
}
Use this simple code:
Firestore.instance.collection("users").document().setData({
"name":"Majeed Ahmed"
});

Flutter Firebase: StreamBuilder Not Listening to Changes?

I'm trying to create a UI where the user submits a "comment" on each "article". As you can see below, in my code, I get username of the user from Firestore and then checks if this user already has a comment for the respective article.
If the comment exists, it returns a stream of all the comments for that given article. If it does not exist, I return the CommentCollector that is a widget to collect the comment and post it to Firestore. This overall works, expect when I submit a comment via CommentCollector, the UserPostGetter widget does not does not rebuild.
How can I trigger this rebuild? I thought using StreamBuilder to listen to see if there is a comment would be enough, but clearly not so. What am I missing?
Really appreciate the help.
class UserPostGetter extends StatelessWidget {
final String articleId;
final String articleHeader;
UserPostGetter({this.articleId, this.articleHeader});
#override
Widget build(BuildContext context) {
// TODO: implement build
return new Scaffold(
body: new Container(
child: new FutureBuilder<FirebaseUser>(
future: FirebaseAuth.instance.currentUser(),
builder: (context, AsyncSnapshot<FirebaseUser> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
String userNumber = snapshot.data.uid;
return new FutureBuilder(
future: getUser(userNumber),
builder: (context, AsyncSnapshot<User> snapshot) {
if (snapshot?.data == null)
return new Center(
child: new Text("Loading..."),
);
String username = snapshot.data.username.toString();
return StreamBuilder(
stream: doesNameAlreadyExist(articleId, username),
builder: (context, AsyncSnapshot<bool> result) {
if (!result.hasData)
return Container(); // future still needs to be finished (loading)
if (result
.data) // result.data is the returned bool from doesNameAlreadyExists
return PostGetter(
articleId: articleId,
);
else
return CommentCollector(
articleID: articleId,
userName: username,
articleTitle: articleHeader,
);
},
);
},
);
} else {
return new Text('Loading...');
}
},
),
),
);
}
}
Stream<bool> doesNameAlreadyExist(String article, String name) async* {
final QuerySnapshot result = await Firestore.instance
.collection('post')
.where('article', isEqualTo: article)
.where('author', isEqualTo: name)
.getDocuments();
final List<DocumentSnapshot> documents = result.documents;
yield documents.length == 1;
}
Future<User> getUser(idNumber) {
return Firestore.instance
.collection('user')
.document('$idNumber')
.get()
.then((snapshot) {
try {
return User.fromSnapshot(snapshot);
} catch (e) {
print(e);
return null;
}
});
}
class User {
String email;
String user_id;
String username;
User.fromSnapshot(DocumentSnapshot snapshot)
: email = snapshot['email'],
user_id = snapshot['user_id'],
username = snapshot['username'];
}

Resources