Loading only specific data from Firestore using StreamBuilder in Flutter/Dart - asynchronous

I am trying to load data from Firestore using StreamBuilder.
In my collection called 'connect' there are may documents.
But I want to load only specific documents.
'connections' is a List that contains some keys in 'connect' collection.
'hello' is a QuerySnapshot List that contains some documents in 'collection' collection.
For example, if my DB contains documents with documentID of followings:
-LK5SAToCPhI1Zp5W_bL
-LK5Ypv0HeDCwcN4K41M
-LK5j-OGtNjMpgklUB4B
-LK5mOih9wuz5ZSebXMn
a list 'connections' contains only a portion such as:
-LK5SAToCPhI1Zp5W_bL
-LK5Ypv0HeDCwcN4K41M
In a StreamBuilder I want to load only documents that have same name in connections. How can I load only specific documents?
Please Help me!
Firestore.instance.collection('connect')
.snapshots()
.listen((docSnap) {
for (DocumentSnapshot docs in docSnap.documents) {
if (connections.isNotEmpty) {
for (String keys in connections) {
if (docs.documentID.toString() == keys) {
hello.add(docs);
}
}
}
}
});
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Center(
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Padding(
padding: EdgeInsets.only(bottom: 60.0),
),
Expanded(
child: Text(
"Invitation!",
style: TextStyle(fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
],
),
Flexible(
child: StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('connect').snapshots(),
builder:
(BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return const Text("Loading ... ");
final int messageCount = snapshot.data.documents.length;
return ListView.builder(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
itemCount: messageCount,
itemBuilder: (_, int index) {
final DocumentSnapshot document =
snapshot.data.documents[index];
if (document.documentID ==
hello[index].documentID) {
return Container(
child: Row(
children: <Widget>[
Text("Hello $messageCount")
],
),
);
} else {
return Container(
child: Row(
children: <Widget>[Text("Wrong")],
),
);
}
});
},
),
),
_buildLayout(),
],
)));
}

Related

Get array collection of an object from firebase flutter

i'm trying to fetch Products collection from specific user, and the request isn't working.
here is my code:
the first request function:
Stream<QuerySnapshot<Object>> get productsUser {
return usersCollection.doc(uid).collection("Products").snapshots();
}
and here where I try to present the Products array I fetch (or didn't...):
class _ProductPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
final GivitUser givitUser = Provider.of<GivitUser>(context);
final DatabaseService db = DatabaseService(uid: givitUser.uid);
return StreamBuilder<QuerySnapshot>(
stream: db.productsUser,
builder: (context, snapshotProduct) {
if (snapshotProduct.hasError) {
return Text('Something went wrong');
}
if (snapshotProduct.connectionState == ConnectionState.waiting) {
return Loading();
}
return Container(
color: Colors.blue[100],
height: 400.0,
alignment: Alignment.topCenter,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: snapshotProduct.data.docs.map(
(DocumentSnapshot document) {
var snapshotdata = document.data() as Map;
Product product =
Product.productFromDocument(snapshotdata, document.id);
print(product.name);
return Container(
child: Text(product.name),
);
},
).toList(),
),
),
);
});
}
}
);
Thanks to everyone who will help! :)
You can either create a StatefulWidget, and store the result of the fetch as state, or you can use a StreamBuilder to manage the state for you, and automatically rebuild the widget tree each time a new snapshot is received. In either case, the following two guides may also be helpful:
Streams
Async/Await
Here's an example of how you might use StreamBuilder in your case:
Widget build(BuildContext context) {
return Container(
color: Colors.blue[100],
height: 400.0,
alignment: Alignment.topCenter,
child: SingleChildScrollView(
child: StreamBuilder<QuerySnapshot<Object>>(
stream: usersCollection.doc(uid).collection("Products").snapshots(),
builder: (context, asyncSnapshot) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: asyncSnapshot.data.data.docs.map(
(DocumentSnapshot document) {
var snapshotdata = document.data() as Map;
Product product =
Product.productFromDocument(snapshotdata, document.id);
print(product.name);
return Container(
child: Text(product.name),
);
},
).toList(),
),
),
),
);
}

Firebase Chat messages not ordering correctly

I have just completed this basic chat app based on a tutorial on YouTube. NO user name needed for using it. But my messages are not ordering correctly. It is sorting as auto generated ID on FireStore. There are total two field in Firebase "message" collection that I have created
"username" {this user name randomly generated by FireBase as user ID. example: 1Mrayhz7EKL7MklHXUxv}
"messagetext"
I don't understanding what should I do now
//Here's the code
class MyApp extends StatelessWidget {
final TextEditingController messaingTextBox = TextEditingController();
final CollectionReference cr =
FirebaseFirestore.instance.collection('messages');
#override
Widget build(BuildContext context) {
body:
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Expanded(
child: StreamBuilder(
stream: cr.snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) return CircularProgressIndicator();
return ListView.builder(
reverse: true,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(18.0),
child: Column(
children: [
Row(
children: [
Container(
child: Padding(
padding: const EdgeInsets.all(6.0),
child: Text(
snapshot.data.documents[index]
.data()['username'],
),
),
),
SizedBox(
width: 10,
),
Container(
// width: 38.0,
width: MediaQuery.of(context).size.width / 1.6,
child: Padding(
padding: const EdgeInsets.all(9.0),
child: Column(
children: [
Text(
snapshot.data.documents[index]
.data()['messagetext'],
),
],
),
),
),
],
),
],
),
);
},
);
},
),
),
Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: TextFormField(
cursorColor: HexColor("#003F51"),
style: TextStyle(color: Colors.black),
controller: messaingTextBox,
),
),
),
FloatingActionButton(
onPressed: () {
Message m = Message(
username: "unkown ",
messagetext: messaingTextBox.text.toString());
cr.add(m.mapMessages());
},
child: Icon(Icons.send),
),
],
),
],
);
}
}
class Message {
final String username;
final String messagetext;
Message({this.messagetext, this.username});
mapMessages() {
return {'messagetext': messagetext, 'username': username};
}
}
Please help me for solving this isue
You need to add third field to store time.
Then in the code try to add orderBy operator.
FirebaseFirestore.instance.collection('messages')
.orderBy('time_field', descending: true);
It's quite simple just add a timestamp with each message lets say createdAt, and the use
NOTE: The type of createdAt must be Date
FirebaseFirestore.instance.collection('messages').orderBy('createdAt', descending: true)

error trying to get a document from firebase using UID, Flutter app

Im getting 2 error in my code trying to get a document from a Firebase collection /users using UID,
base on this document FlutterFire
First one => error: Too many positional arguments: 0 expected, but 1 found. (extra_positional_arguments_could_be_named at [calfran_app] lib/pages/home.dart:49)`
Second one => error: Undefined name 'users'. (undefined_identifier at [calfran_app] lib/pages/home.dart:37)
class _HomeState extends State<Home> {
Widget build(BuildContext context) {
Stream documentStream = FirebaseFirestore.instance.collection('users').doc('user.uid').snapshots();
int _currentIndex = 0;
final tabs = [
//TAB DE MANUAIS
Center(
child: (Scaffold(
body: StreamBuilder<QuerySnapshot>(
stream: users.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return Container(
padding: EdgeInsets.all(16),
child: ListView(
snapshot.data.documents.map((DocumentSnapshot document) {
var dio = Dio();
return Card(
color: Colors.grey[250],
child: Container(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Image.asset(
'Images/pdflogo.png', width: 32,
),
Center(
child: Text(
(document.data()['nome'].toString()),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 16),
),
),
ButtonBar(
children: <Widget>[
FlatButton(
child: const Text(
'Compartilhar / Download'),
onPressed: () async {
var request = await HttpClient()
.getUrl(Uri.parse(
document.data()['documento']));
var response = await request
.close();
Uint8List bytes = await consolidateHttpClientResponseBytes(
response);
await Share.file(
'ESYS AMLOG',
'Manual.pdf',
bytes,
'image/jpg');
}),
],
),
],
),
),
);
}),
));
})))),

How to get it from userUid() to the StreamBuilder Flutter

i was wondering how can i pass my function userUid() to the StreamBuilder {
FirebaseAuth auth = FirebaseAuth.instance;
userUid() async {
final FirebaseUser user = await auth.currentUser;
final uid = user.uid;
return uid;
}
Where I want to pass it, to get the document base on the logged user UID.
final tabs = [
final documentId = await userUid();
Center(
child: (Scaffold(
body: StreamBuilder (
stream: FirebaseFirestore.instance.collection('users').document(userUid()).snapshots(),
builder: (context, snapshot) {
if (snapshot.data == null) return CircularProgressIndicator();
return Container(
padding: EdgeInsets.all(16),
child: ListView.builder(
When I Pass the function final documentId = await useruid();inside the final tabs =[
I get the error
error: Expected an identifier. (missing_identifier at lib/pages/home.dart:39)
error: Expected to find ']'. (expected_token at lib/pages/home.dart:39)
idk what I can do to pass this function...
with someone know a document of example so i can study how to do it,
full code:
final tabs = [
final documentId = await userUid();
Center(
child: (Scaffold(
body: StreamBuilder (
stream: FirebaseFirestore.instance.collection('users').document(userUid()).snapshots(),
builder: (context, snapshot) {
if (snapshot.data == null) return CircularProgressIndicator();
return Container(
padding: EdgeInsets.all(16),
child: ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot manuais =
snapshot.data.documents[index];
return Card(
color: Colors.grey[250],
child: Container(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Image.asset('Images/pdflogo.png', width: 32,
),
Center(
child: Text(
(manuais.data()['nome'].toString()),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 16),
),
),
ButtonBar(
children: <Widget>[
FlatButton(
child: const Text('Compartilhar / Download'),
onPressed: () async {
var request = await HttpClient().getUrl(Uri.parse(manuais.data()['documento']));
var response = await request.close();Uint8List bytes = await consolidateHttpClientResponseBytes(response);
await Share.file(
'ESYS AMLOG',
'Manual.pdf',
bytes,
'image/jpg');
}),
],
),
],
),
),
);
}),
);
})))),
Center(
child: (Scaffold(
body: StreamBuilder(
stream: FirebaseFirestore.instance.collection('producao').snapshots(),
builder: (context, snapshot) {
if (snapshot.data == null) return CircularProgressIndicator();
return Container(
padding: EdgeInsets.all(16),
child: ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot producao =
snapshot.data.documents[index];
return Card(
color: Colors.grey[250],
child: Container(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Center(
child: Image.network(producao.data()['img'].toString(), width: 260,
),
),
Text(
(producao.data()['data'].toString()),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 22),
),
Text(
(producao.data()['detail'].toString()),
style: TextStyle(fontSize: 16),
),
ButtonBar(
children: <Widget>[
FlatButton(
child: const Text('DETALHES'),
onPressed: () {
ImageViewer.showImageSlider(
images: [
(producao.data()['img']),
//List of images' URLs
],
);
}),
FlatButton(
child: const Text('COMPARTILHAR'),
onPressed: () async {
var request = await HttpClient().getUrl(Uri.parse(producao.data()['img']));
var response = await request.close();Uint8List bytes = await consolidateHttpClientResponseBytes(response);
await Share.file(
'ESYS AMLOG',
'amlog.jpg',
bytes,
'image/jpg'
);
}),
],
),
],
),
),
);
}),
);
})))),
Center(child: Text('Documentos')),
]; //<<<<<<<<<<<<<<< here closes the tab
````
You cannot define a variable inside a List. You could do two things:
Declare the documentId before the List instantiation:
final documentId = await userUid();
final tabs = [
...
];
Create a function that returns a list:
/// ... simulates the parameters of the function
List<Widget> getWidgetList(...) async {
final documentId = await userUid();
final List<Widget> list = [];
// To insert in a final list use the method add(...)
...
// Do your logic here
...
return list;
}
final tabs = getWidgetList(...);

Stream builder from firestore to flutter

I am wondering how to get data from firestore to flutter app using the streambuilder. I created the necessary Boilerplate code I have the widget built and working and in the below code
headimageassetpath is nothing but a URL string which exists in the firestore.
#override
Widget build(BuildContext context) {
return Scaffold(
body:
new StreamBuilder(
stream: Firestore.instance.collection('Items').snapshots(),
builder: (_, AsyncSnapshot<QuerySnapshot> snapshot) {
var items = snapshot.data?.documents ?? [];
return new Lost_Card(
headImageAssetPath : snapshot.data.documents.map()(['url'],)
);
},
)
My firestore:
full code:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class LostPage extends StatefulWidget {
#override
_LostPage createState() => new _LostPage();
}
class _LostPage extends State<LostPage> {
//temp vars
final String firebasetest = "Test";
//firestore vars
final DocumentReference documentReference =
Firestore.instance.document("Items/Rusty");
//CRUD operations
void _add() {
Map<String, String> data = <String, String>{
"name": firebasetest,
"desc": "Flutter Developer"
};
documentReference.setData(data).whenComplete(() {
print("Document Added");
}).catchError((e) => print(e));
}
#override
Widget build(BuildContext context) {
return Scaffold(
body:
new StreamBuilder(
stream: Firestore.instance.collection('Items').snapshots(),
builder: (_, AsyncSnapshot<QuerySnapshot> snapshot) {
var items = snapshot.data?.documents ?? [];
return new Lost_Card(
headImageAssetPath : snapshot.data.documents.map()(['url'],)
);
},
)
/*new Lost_Card(
headImageAssetPath: "https://i.imgur.com/FtaGNck.jpg" ,
title: "Mega Dish",
noro: "old",
)*/,
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.add),
onPressed: _add),
);
}
}
class Lost_Card extends StatelessWidget
{
//All the card variables
final String headImageAssetPath;
final IconData icon;
final Color iconBackgroundColor;
final String title;
final String noro;
final int price;
final ShapeBorder shape;
Lost_Card({
this.headImageAssetPath, //used
this.icon,
this.iconBackgroundColor,
this.title, //used
this.noro, //used
this.price,
});
#override
Widget build(BuildContext context) {
// TODO: implement build
return GridView.count(
shrinkWrap: true,
crossAxisCount: 2,
children: <Widget>[
Card(
child: Column(
// mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height / 4,
width: MediaQuery.of(context).size.height / 2.5,
child: DecoratedBox(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
headImageAssetPath),
fit: BoxFit.cover),
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Align(
alignment: FractionalOffset.topLeft,
child: CircleAvatar(
backgroundColor: Colors.redAccent,
radius: 15.0,
child: Text(
noro,
textScaleFactor: 0.5,
),
),
),
),
Align(
alignment: FractionalOffset.topRight,
child: Container(
color: Colors.blueAccent,
height: 35.0,
width: 35.0,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.account_circle),
Text(
"1P",
textScaleFactor: 0.5,
),
],
),
),
),
),
],
),
),
Center(
child: Container(
padding: const EdgeInsets.all(8.0),
alignment: FractionalOffset.bottomCenter,
child: Text(
title,
style: TextStyle(
fontWeight: FontWeight.w700,
),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
FlatButton(
child: Text(
"Add To Cart",
style: TextStyle(color: Colors.grey[500]),
),
onPressed: () => null,
),
Text(
"\$5",
style: TextStyle(color: Colors.grey[500]),
)
],
)
],
),
),
],
);
}
}
Actual App
Please shed some light on this. Tks.
This should work for one item
body: new StreamBuilder(
stream: Firestore.instance.collection("collection").snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Text(
'No Data...',
);
} else {
<DocumentSnapshot> items = snapshot.data.documents;
return new Lost_Card(
headImageAssetPath : items[0]["url"]
);
}
If you want to create list builder from many documents use it like this
return new ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot ds = snapshot.data.documents[index];
return new Lost_Card(
headImageAssetPath : ds["url"];
);
Accessing documents using StreamBuilder in Flutter 2
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection('products').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot doc = snapshot.data!.docs[index];
return Text(doc['name']);
});
} else {
return Text("No data");
}
},
)
As per new changes 2021 in Firebase FireStore you can retrieve data from collection using StreamBuilder as below
final _mFirestore = FirebaseFirestore.instance;
return StreamBuilder<QuerySnapshot>(
stream:
_mFirestore.collection(kFirebaseCollectionName).snapshots(),
builder: (context, snapshots) {
if (!snapshots.hasData) {
return Center(
child: Text('Data not available',),
);
}
final messages = snapshots.data.docs;
List<Text> textWidgets = [];
messages.forEach((element) {
final messageText = element['text'];
final messageSender = element['sender'];
final textWidget = Text('$messageText, $messageSender');
textWidgets.add(messageBubbleWidget);
});
},
);
Card buildItem(DocumentSnapshot doc) {
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'name: ${doc.data['name']}',
style: TextStyle(fontSize: 24),
),
Text(
'todo: ${doc.data['todo']}',
style: TextStyle(fontSize: 20),
),
Text(
'Age: ${doc.data['age']}',
style: TextStyle(fontSize: 10),
),
SizedBox(
height: 12,
),
],
)
],
),
),
); }
For other persons who will face the same problem, the card and stream builder will represent a solution. The Widget has the Card just before it declaration and has inside the body the next part:
body: ListView(
padding: EdgeInsets.all(8),
children: <Widget>[
Form(
key: _formKey,
child: buildTextFormField(),
),
StreamBuilder<QuerySnapshot>(
stream: db
.collection('CRUD')
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children: snapshot.data.documents
.map((doc) => buildItem(doc))
.toList());
} else {
return SizedBox();
}
},
)
],
),
Update for 2022, Flutter 2.10, cloud_firestore: ^3.1.11. You can retrieve data from collection using StreamBuilder
Stream collectionStream = FirebaseFirestore.instance.collection('users').snapshots();
StreamBuilder<QuerySnapshot>(
builder: (context, snapshot) {
if (snapshot.hasData) {
final messages = snapshot.data!.docs;
List<Text> messageWidgets = [];
for (var element in messages) {
final messageText = element['text'];
final messageSender = element['sender'];
final messageWidget =
Text('$messageText from $messageSender');
messageWidgets.add(messageWidget);
}
return Column(
children: messageWidgets,
);
}
return const Text('Error');
},
stream:collectionStream),
StreamBuilder<List<UData>>(
stream: AdminData().getDrivers,
builder: (context, snapshot) {
return ListView(
children: snapshot.data.map((document) {
return hadCard(
widget: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
hadText(title: document.name),
hadText(title: document.phone),
hadText(title: document.Driver),
],
),
);
}).toList(),
);
}),

Resources