How to get document id in firestore flutter using QuerySnapshot - firebase

I am trying to get data (In real-time) from my database using QuerySnapshot.
and I need to update my data as well. This is my method and I don't know how to get my documentID in this method.
class LoadData extends StatefulWidget {
const LoadData({Key? key}) : super(key: key);
#override
_LoadDataState createState() => _LoadDataState();
}
class _LoadDataState extends State<LoadData> {
//Read Data in realTime Snapshot
final Stream<QuerySnapshot> _cupCakeStream = FirebaseFirestore.instance
.collection('cupcake')
.snapshots(includeMetadataChanges: true);
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _cupCakeStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return ListView(
shrinkWrap: true,
children: snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
print(data); //**Print collection only..I need to get documentID with each collection**
return ListTile(
title: Text(data['cupcake_name']),
subtitle: Text(data['description']),
);
}).toList(),
);
},
);
}
}

document is a DocumentSnapshot and has an id property.
So, the following should do the trick:
return ListView(
shrinkWrap: true,
children: snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
print(data);
print(document.id); // <= Should print the doc id
return ListTile(
title: Text(data['cupcake_name']),
subtitle: Text(data['description']),
);
}).toList(),
);

Related

How to display Image in App with flutter and firebase using URL as String in Firestore

we have no clue how to display an image in a flutter app via an URL from Firebase Firestore.
Here is a Picture of our database with three fields one of which is for a picture. In that we placed the URL of the Image we want to display.
We know how to display Text from that database, as you can see in our code. Now we want to simply display an image from the database.
Currently we use Image() with NetworkImage() where we placed a var "imageURL". That works fine.
How can we tell the var "ImageURL" to use the URL out of the database.
Here is our code:
class DataFavorites extends StatefulWidget {
const DataFavorites({Key? key}) : super(key: key);
#override
_DataFavoritesState createState() => _DataFavoritesState();
}
class _DataFavoritesState extends State<DataFavorites> {
var imageURL = 'https://previews.123rf.com/images/gumbao/gumbao1509/gumbao150900016/44987080-kiefer-firest-auf-la-marina-an-der-k%C3%BCste-des-mittelmeers-costa-blanca-spanien.jpg';
final Stream<QuerySnapshot> _data = FirebaseFirestore.instance.collection('favoriten').snapshots();
#override
Widget build(BuildContext context) {
return Scaffold(
body:
StreamBuilder<QuerySnapshot>(
stream: _data,
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['Name'],style: Theme.of(context).textTheme.headline1,
),
subtitle: Image(
image: NetworkImage(imageURL),
width: 300,
height: 300,
),
);
}).toList(),
);
},
),
);
}
}
Thanks in advance!
You should give the parameter of image url to the NetworkImage widget
You code should look like this
class DataFavorites extends StatefulWidget {
const DataFavorites({Key? key}) : super(key: key);
#override
_DataFavoritesState createState() => _DataFavoritesState();
}
class _DataFavoritesState extends State<DataFavorites> {
var imageURL = 'https://previews.123rf.com/images/gumbao/gumbao1509/gumbao150900016/44987080-kiefer-firest-auf-la-marina-an-der-k%C3%BCste-des-mittelmeers-costa-blanca-spanien.jpg';
final Stream<QuerySnapshot> _data = FirebaseFirestore.instance.collection('favoriten').snapshots();
#override
Widget build(BuildContext context) {
return Scaffold(
body:
StreamBuilder<QuerySnapshot>(
stream: _data,
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['Name'],style: Theme.of(context).textTheme.headline1,
),
subtitle: Image(
image: NetworkImage(data['Bild']), // ----------- the line that should change
width: 300,
height: 300,
),
);
}).toList(),
);
},
),
);
}
}

Flutter - How can I print all my data (fields) from firebase documents?

I would like to show all the fields of a document in firebase, but I'm having different troubles.
My intention is to show the info like a chat. I tried with a ListView.builder inside a StreamBuilder.
This is my Firestore document:
I managed to get the horizontal information using doc.data().toString but what I am trying to do is to get the whole information as a ListTile so when I add new messages they are automatically added to the ListView.builder.
This is my current code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class ChatScreen extends StatefulWidget {
const ChatScreen({Key? key}) : super(key: key);
#override
State<ChatScreen> createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
final textController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.only(left: 20.0),
child: StreamBuilder(
stream:
FirebaseFirestore.instance.collection("messages").snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
}
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot doc = snapshot.data!.docs[index];
return ListTile(
title: Text(doc.data().toString()),
);
},
);
}),
),
);
}
}
And this is what I get with my current code: DeviceImage
P.S. I can get the data manually if I use this but it's not what I want:
return ListTile(
title: Text(doc['sender']),
);
Try to use an Object like below.
class Message {
final String sender;
final String text;
const Message({
required this.sender,
required this.text,
});
Map<String, dynamic> toMap() {
return {
'sender': sender,
'text': text,
};
}
factory Message.fromMap(Map<String, dynamic> map) {
return Message(
sender: map['sender'] as String,
text: map['text'] as String,
);
}
}
class ChatScreen extends StatelessWidget {
const ChatScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamBuilder<List<Message>>(
stream: FirebaseFirestore.instance
.collection("messages")
.snapshots()
.map((query) =>
query.docs.map((map) => Message.fromMap(map.data())).toList()),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
final msgList = snapshot.data!;
return ListView.builder(
itemCount: msgList.length,
itemBuilder: (context, index) {
final message = msgList[index];
return ListTile(
title: Text(message.text),
leading: Text(message.sender),
);
},
);
});
}
}
Try with this.
return StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection("messages")
.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
return ListView.builder(
shrinkWrap: true,
primary: false,
itemCount: snapshot.hasData ? snapshot.data.docs.length : 0,
itemBuilder: (context, index) {
final data = MessageModel.fromSnapshot(snapshot.data.docs[index]);
return ListTile(
title: Text(data.text),
subtitle: Text(data.sender),
);
},
);
},
);
MessageModel
class MessageModel {
MessageModel({
this.sender,
this.text,
});
String sender;
String text;
String toRawJson() => json.encode(toJson());
factory MessageModel.fromSnapshot(DocumentSnapshot snapshot) {
final model =
MessageModel.fromJson(snapshot.data() as Map<String, dynamic>);
return model;
}
factory MessageModel.fromJson(Map<String, dynamic> json) => MessageModel(
sender: json["sender"] == null ? null : json["sender"],
text: json["text"] == null ? null : json["text"],
);
Map<String, dynamic> toJson() => {
"sender": sender == null ? null : sender,
"text": text == null ? null : text,
};
}

Flutter Firestore Stream builder "A value of type 'Stream<DocumentSnapshot<Map<String, dynamic>>>' can't be assigned to a variable"

I am trying to retrieve data from my Firestore database via a Streambuilder. The issue I have comes from an error from the following error when I add my doc(uid) into my _usersStream:
A value of type 'Stream<DocumentSnapshot<Map<String, dynamic>>>' can't be assigned to a variable of type 'Stream<QuerySnapshot<Object?>>'.
Try changing the type of the variable, or casting the right-hand type to 'Stream<QuerySnapshot<Object?>>'.
I was wondering how to how to rectify this error. Here is my code:
class _UserProfileScreenState extends State<UserProfileScreen> {
final Stream<QuerySnapshot> _usersStream = FirebaseFirestore.instance.collection('users').doc(uid).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("");
}
return Scaffold(
appBar: ProfileAppBar(),
body: ListView(
children: snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return ListTile(
title: Text(data['username']),
subtitle: Text(data['displayName']),
);
}).toList(),
),
);
},
);
}
}
There is some issue when you define _userStream
final Stream<QuerySnapshot> _usersStream = FirebaseFirestore.instance.collection('users').doc(uid).snapshots();
_userStream is a value of type Stream<DocumentSnapshot<Map<String, dynamic>>>
_userStream should be like this.
final Stream<DocumentSnapshot<Map<String, dynamic>>> _usersStream = FirebaseFirestore.instance.collection('users').doc(uid).snapshots();
it is better to use FutureBuilder
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() as Map<String, dynamic>;
return Text("Full Name: ${data['full_name']} ${data['last_name']}");
}
return Text("loading");
},
);
}
}
Please check this guide

my Stream is not updating when isTeacher() function is called

what I am trying to achieve is load data from a specific collection(teacher) of my database. So I am using a function called isTeacher(). which checks if the current user's uid belongs in that collection. if not then it is a student. it stores the value in a string called value. so when I am using stream builder to load data available in their specific collection or documents, my stream builder shows circular progress and after that, it doesn't load the data. Any help is appreciated.
Thank you
`class MyClasses extends StatefulWidget {
#override
_MyClasses createState() => _MyClasses();
}
String value;
String classPassword;
List<dynamic> catchUserDetails = [];
class _MyClasses extends State<MyClasses> {
Future isTeacher() {
return FirebaseFirestore.instance
.collection('teacher')
.doc(FirebaseAuth.instance.currentUser.uid)
.get()
.then((DocumentSnapshot doc) {
value = doc.exists.toString();
print(doc.data());
print(value);
print('isteacher called in method');
});
}
#override
Widget build(BuildContext context) {
isTeacher();
return Scaffold(
body: SafeArea(
child: StreamBuilder(
stream: FirebaseFirestore.instance
.collection(value)
.doc(FirebaseAuth.instance.currentUser.uid)
.collection('class')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent,
),
);
} else {
final messages = snapshot.data.documents.reversed;
List<GenerateClass> messageBubbles = [];
for (var message in messages) {
final messageText = message.data()['className'];
final messageBubble = GenerateClass(
classID: messageText,
//nnouncementID: i,
);
messageBubbles.add(messageBubble);
}
return ListView(
//itemExtent: 100,
children: messageBubbles,
);
}
},
),
),
);`
Solved it by using a FutureBuilder
FutureBuilder(
future: isTeacher(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return StreamBuilder();

how to get data from firebase in flutter

I am building a flutter app and using cloud-firestore,
this is how my database looks like
I want a function that retrieves all documents in the collection called "Driver List" in an array of strings
that what I had already used but it gets them back in a listview in a new screen
class DriverList extends StatelessWidget {#overrideWidget build(BuildContext context) {
return new StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('DriverList').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['name']),
subtitle: new Text(document['phone']),
);
}).toList(),
);
},
);
}
}
This has some additional logic to remove potentially duplicate records, but you can use something like the following to retrieve data from Firestore.
We get access to a collection reference, then list the results of the query, then create local model objects for the data returned by Firestore, and then we return the a list of those model objects.
static Future<List<AustinFeedsMeEvent>> _getEventsFromFirestore() async {
CollectionReference ref = Firestore.instance.collection('events');
QuerySnapshot eventsQuery = await ref
.where("time", isGreaterThan: new DateTime.now().millisecondsSinceEpoch)
.where("food", isEqualTo: true)
.getDocuments();
HashMap<String, AustinFeedsMeEvent> eventsHashMap = new HashMap<String, AustinFeedsMeEvent>();
eventsQuery.documents.forEach((document) {
eventsHashMap.putIfAbsent(document['id'], () => new AustinFeedsMeEvent(
name: document['name'],
time: document['time'],
description: document['description'],
url: document['event_url'],
photoUrl: _getEventPhotoUrl(document['group']),
latLng: _getLatLng(document)));
});
return eventsHashMap.values.toList();
}
Source: https://github.com/dazza5000/austin-feeds-me-flutter/blob/master/lib/data/events_repository.dart#L33
Getting one time data:
var collection = FirebaseFirestore.instance.collection('DriverList');
var querySnapshot = await collection.get();
for (var queryDocumentSnapshot in querySnapshot.docs) {
Map<String, dynamic> data = queryDocumentSnapshot.data();
var name = data['name'];
var phone = data['phone'];
}
Getting data each time it changes, using a StreamBuilder:
StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance.collection('DriverList').snapshots(),
builder: (_, snapshot) {
if (snapshot.hasError) return Text('Error = ${snapshot.error}');
if (snapshot.hasData) {
final docs = snapshot.data!.docs;
return ListView.builder(
itemCount: docs.length,
itemBuilder: (_, i) {
final data = docs[i].data();
return ListTile(
title: Text(data['name']),
subtitle: Text(data['phone']),
);
},
);
}
return Center(child: CircularProgressIndicator());
},
)
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class LoadDataFromFirestore extends StatefulWidget {
#override
_LoadDataFromFirestoreState createState() => _LoadDataFromFirestoreState();
}
class _LoadDataFromFirestoreState extends State<LoadDataFromFirestore> {
#override
void initState() {
super.initState();
getDriversList().then((results) {
setState(() {
querySnapshot = results;
});
});
}
QuerySnapshot querySnapshot;
#override
Widget build(BuildContext context) {
return Scaffold(
body: _showDrivers(),
);
}
//build widget as prefered
//i'll be using a listview.builder
Widget _showDrivers() {
//check if querysnapshot is null
if (querySnapshot != null) {
return ListView.builder(
primary: false,
itemCount: querySnapshot.documents.length,
padding: EdgeInsets.all(12),
itemBuilder: (context, i) {
return Column(
children: <Widget>[
//load data into widgets
Text("${querySnapshot.documents[i].data['activation']}"),
Text("${querySnapshot.documents[i].data['car1']}"),
Text("${querySnapshot.documents[i].data['car2']}"),
Text("${querySnapshot.documents[i].data['car5']}"),
Text("${querySnapshot.documents[i].data['name']}"),
Text("${querySnapshot.documents[i].data['phone']}"),
],
);
},
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}
//get firestore instance
getDriversList() async {
return await Firestore.instance.collection('DriversList').getDocuments();
}
}
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StreamBuilder(
stream:
FirebaseFirestore.instance.collection('messages').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(snapshot.error.toString()),
);
}
if (snapshot.hasData) {
final messages = snapshot.data!.docs;
List<Text> messageWigdets = [];
for (var message in messages) {
final messageText = message['text'];
final messageSender = message['sender'];
final messageWigdet =
Text('$messageText from $messageSender');
messageWigdets.add(messageWigdet);
}
return Expanded(
child: ListView(
children: [...messageWigdets],
),
);
}
return const CircularProgressIndicator.adaptive();
},
),

Resources