How can I read the data in firebase with flutter - firebase

I tried some things but I cant read the data. I'm a beginner in flutter and I have to do a project that it shows the data in firebase. Can you show a beginner project that it only shows the datas in direbase?
I tried this too but this code have some errors on await (how it's possible I copied this from flutter official site)
import 'package:firebase_database/firebase_database.dart';
DatabaseReference ref = FirebaseDatabase.instance.ref("users/123");
// Get the data once
DatabaseEvent event = await ref.once();
// Print the data of the snapshot
print(event.snapshot.value);
Thanks for replys I checked the await keyword and correct them (I think)
But I dont know how to print this
Can you show me that too
And I edited code to this =>
Future<Object?> GetData() async {
FirebaseDatabase database = FirebaseDatabase.instance;
DatabaseReference ref = FirebaseDatabase.instance.ref("litre");
// Get the data once
DatabaseEvent event = await ref.once();
// Print the data of the snapshot
print(event.snapshot.value); // { "name": "John" }
return event.snapshot.value;
}

Wherever you're calling the GetData method you need to await it...or if it is a widget which needs to display data after fetching it from firebase you can wrap it with a future builder.
I hope this solves your problem, if it still doesn't, post with the specific error you're getting.
FutureBuilder(
future: GetData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else {
if (snapshot.error != null) {
return Center(
child: Text('An error occured'),
);
} else {
return Text(snapshot.data); // Or whatever widget you want to return or display
}
}
},
),

Related

Flutter Firestore: FirestoreBuilder with initial data

I'm making my first Flutter app and I encounter a problem and doesn't found any solution for it.
I have a view where I render a Firestore document, and there is two ways of getting there:
From a list where I already loaded my documents
From Dynamic Links with uid attached as arguments (args)
So in order to listen document changes and loading the data when arriving from the link I used FirestoreBuilder like this:
return FirestoreBuilder<EventDocumentSnapshot>(
ref: eventsRef.doc(args.uid),
builder: (context, AsyncSnapshot<EventDocumentSnapshot> snapshot, Widget? child) {
if (!snapshot.hasData) {
return Container();
}
Event? event = snapshot.requireData.data;
return Scafold(); //Rest of my rendering code
}
);
How I could avoid first call to Firebase when I already have the data but still listen to changes? The main problem is that my hero animation doesn't work because of this.
I tried with a StreamBuilder and initialDataparam but since it's expecting stream I didn't know how to cast my data.
Okay, so I found the solution myself after many tries, so I added my Model object that can be null as initialData, but the thing that makes me struggle with is how you get the data in the builder. You have to call different methods depending on where the data is coming from.
return StreamBuilder(
initialData: args.event
ref: eventsRef.doc(args.uid),
builder: (context, AsyncSnapshot<dynamic> snapshot) {
// Here is the trick, when data is coming from initialData you only
// need to call requireData to get your Model
Event event = snapshot.requireData is EventDocumentSnapshot ? snapshot.requireData.data : snapshot.requireData;
return Scafold(); //Rest of my rendering code
}
);
Reading through cloud_firestore's documentation you can see that a Stream from a Query can be obtained via snapshots()
StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('books').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return new Text('Loading...');
return new ListView(
children: snapshot.data.documents.map((DocumentSnapshot document) {
return new ListTile(
title: new Text(document['title']),
subtitle: new Text(document['author']),
);
}).toList(),
);
},
);
This won't help you, but with GetX it's simple to implement like this: You don't need StreamBuilder anymore.
//GetXcontroller
class pageController extends GetXcontroller {
...
RxList<EventModel> events = RxList<EventModel>([]);
Stream<List<EventModel>> eventStream(User? firebaseUser) =>
FirebaseFirestore.instance
.collection('events')
.snapshots()
.map((query) =>
query.docs.map((item) => UserModel.fromMap(item)).toList());
#override
void onReady() async {
super.onReady();
events.bindStream(
eventStream(controller.firebaseUser)); // subscribe any change of events collection
}
#override
onClose() {
super.onClose();
events.close(); //close rxObject to stop stream
}
...
}
You can use document snapshots on StreamBuilder.stream. You might want to abstract the call to firebase and map it to an entity you defined.
MyEntity fromSnapshot(DocumentSnapshot<Map<String, dynamic>> snap) {
final data = snap.data()!;
return MyEntity (
id: snap.id,
name: data['name'],
);
}
Stream<MyEntity> streamEntity(String uid) {
return firebaseCollection
.doc(uid)
.snapshots()
.map((snapshot) => fromSnapshot(snapshot));
}
return StreamBuilder<MyEntity>(
// you can use firebaseCollection.doc(uid).snapshots() directly
stream: streamEntity(args.uid),
builder: (context, snapshot) {
if (snapshot.hasData) {
// do something with snapshot.data
return Scaffold(...);
} else {
// e.g. return progress indicator if there is no data
return Center(child: CircularProgressIndicator());
}
},
);
For more complex data models you might want to look at simple state management or patterns such as BLoC.

flutter firebase get string from database using future

I want to get a string from my DB in Firebase, I'm very confused and I don't know how to do that!
I made a big search in the few past days about this idea but unf I don't get any useful result
what do I want? I want to make a Method that returns the 'Question' string.
DB:Collection / History/question
thank you for your time
the incorrect code :
Future loadData() async {
await Firebase.initializeApp();
if (snapshot.hasError) {
return Scaffold(
body: Center(
child: Text("Error: ${snapshot.error}"),
),
);
}
// Collection Data ready to display
if (snapshot.connectionState == ConnectionState.done) {
// Display the data inside a list view
return snapshot.data.docs.map(
(document) {
return method(
document.data()['question'].toString().toString(),
); //Center(
},
);
}
}
Here is the official documentation from Flutter Fire - https://firebase.flutter.dev/docs/firestore/usage/
Read data from Cloud firestore
Cloud Firestore gives you the ability to read the value of a collection or a document. This can be a one-time read or provided by real-time updates when the data within a query changes.
One-time Read
To read a collection or document once, call the Query.get or DocumentReference.get methods. In the below example a FutureBuilder is used to help manage the state of the request:
class GetUserName extends StatelessWidget {
final String documentId;
GetUserName(this.documentId);
#override
Widget build(BuildContext context) {
CollectionReference users = FirebaseFirestore.instance.collection('users');
return FutureBuilder<DocumentSnapshot>(
future: users.doc(documentId).get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.hasData && !snapshot.data.exists) {
return Text("Document does not exist");
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data = snapshot.data.data();
return Text("Full Name: ${data['full_name']} ${data['last_name']}");
}
return Text("loading");
},
);
}
}
To learn more about reading data whilst offline, view the Access Data Offline documentation.
Realtime changes
FlutterFire provides support for dealing with real-time changes to collections and documents. A new event is provided on the initial request, and any subsequent changes to collection/document whenever a change occurs (modification, deleted, or added).
Both the CollectionReference & DocumentReference provide a snapshots() method which returns a Stream:
Stream collectionStream = FirebaseFirestore.instance.collection('users').snapshots();
Stream documentStream = FirebaseFirestore.instance.collection('users').doc('ABC123').snapshots();
Once returned, you can subscribe to updates via the listen() method. The below example uses a StreamBuilder which helps automatically manage the streams state and disposal of the stream when it's no longer used within your app:
class UserInformation extends StatefulWidget {
#override
_UserInformationState createState() => _UserInformationState();
}
class _UserInformationState extends State<UserInformation> {
final Stream<QuerySnapshot> _usersStream = FirebaseFirestore.instance.collection('users').snapshots();
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _usersStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return new ListView(
children: snapshot.data.docs.map((DocumentSnapshot document) {
return new ListTile(
title: new Text(document.data()['full_name']),
subtitle: new Text(document.data()['company']),
);
}).toList(),
);
},
);
}
}
By default, listeners do not update if there is a change that only affects the metadata. If you want to receive events when the document or query metadata changes, you can pass includeMetadataChanges to the snapshots method:
FirebaseFirestore.instance
.collection('users')
.snapshots(includeMetadataChanges: true)

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"
});

Flutter StreamBuilder for multiple firebase documents

I am trying to make my Flutter app update when a change is made to the usersCollection.document(user.uid) firebase document.
When the user document is updated I want to retrieve the data from this document but also from another firebase document, facilitiesCollection.document(...).
My current code
Future<Map> _getCheckedInFacilityData() async {
Map<String, dynamic> result = {};
try {
DocumentSnapshot userDoc =
await _db.usersCollection.document(user.uid).get();
if (userDoc.data['checkedIn']) {
// User is checked in
DocumentSnapshot facDoc = await _db.facilitiesCollection
.document(userDoc.data['activeFacilityID'].toString())
.get();
result['facilityID'] = userDoc.data['activeFacilityID'];
result['sessionID'] = userDoc.data['activeSessionID'];
result['facilityActiveUsers'] = facDoc.data['activeUsers'].length;
result['facilityName'] = facDoc.data['name'];
return result;
}
} catch (er) {
debugPrint(er.toString());
}
return null;
}
FutureBuilder<Map>(
future: _getCheckedInFacilityData(),
builder: (context, map) {
switch (map.connectionState) {
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
...
This is currently working but the page is not updated when a change is made to the user document.
I haven't been using Flutter/Dart for long so any ideas are welcome.
Is it possible to return a custom object/map which is comprised of 2 separate documents from a StreamBuilder, or is there another method that will work in my situation.
Surely you can do it with Streams asyncMap() and then listen in StreamBuilder
Basic algoritm
Get stream of you first data type and then asyncMap to wait second data type and return them both
stream.asyncMap(
(v1) async {
final v2 = await Future.delayed(Duration(seconds: 1), () => 4);
return v1 * v2;
},
);
Closer to your code
Stream<Map<String, dynamic>> _getCheckedInFacilityData() {
return _db.usersCollection.document(user.uid).snapshots()
.asyncMap(
(userDoc) async {
final DocumentSnapshot facDoc =
await _db.facilitiesCollection
.document(userDoc.data['activeFacilityID'].toString())
.get();
final Map<String, dynamic> userMap = userDoc.data;
final Map<String, dynamic> facMap = facDoc.data;
return userMap..addAll(facMap);
},
);
}
In this function I merge two maps - be carefull if both maps have identical keys map will keep only last was added key in our case from addAll(facMap)
Last step is to show you streamed data on screen - use StreamBuilder
StreamBuilder<Map>(
stream: _getCheckedInFacilityData(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('${snapshot.error}');
} else if (snapshot.connectionState == ConnectionState.waiting) {
return LinearProgressIndicator();
}
return /* some widget that shows your data*/;
},
),

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"
});

Resources