Search Function in Firestore Flutter - firebase

I'm trying to search for current chats in firestore by the user name but I get here all the chats I have even when I type a letter that is not included
Stream<QuerySnapshot<Map<String, dynamic>>> chatsSearchService(
String userId, String searchValue) {
return FirebaseFirestore.instance
.collection('users')
.doc(userId)
.collection('chats')
.where('userName', isEqualTo: searchValue)
.snapshots();
I want to only get the chat which contains the letters I type
StreamBuilder(
stream: FirestoreServices()
.chatsSearchService('${cubit.userModel?.id}', cubit.searchValue),
builder: (context,
AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snap) {
if (!snap.hasData) {
return Container();
}
return ListView.separated(
physics: BouncingScrollPhysics(),
itemBuilder: (context, index) {
LastMessagesModel currentChats =
LastMessagesModel.fromJson(snap.data?.docs[index].data());
return InkWell(
child: searchChatBody(user, context, currentChats),
);
},
separatorBuilder: (context, index) {
return Divider();
},
itemCount: snap.data!.docs.length);
}),

Related

Flutter/Dart Stream Builder Multiple Collections Firebase

I know there's probably a better way to do this but would like if its possible, to maintain the current DB structure.. (see attached)
DB Collections
Question: How can I return a StreamBuilder with a Listview(child:listTile) that displays profiles for all UID's that a particular user is following(eg: return user profiles that user "BHRaCBR.." is following). In this case im BHRaCBR...
Code below works but only returns one listTile (user):
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('following')
.doc('BHRaCBR..')
.collection('userFollowing')
.where('isApproved', isEqualTo: true)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
}
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot ds = snapshot.data.documents[index];
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('profile')
.where('uid', isEqualTo: ds['uid'])
.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
}
final data0 = snapshot.data.docs;
return Container(
height: 200,
child: ListView.builder(
itemCount: data0.length,
itemBuilder: (BuildContext ctx, index) {
return Card(
child: ExpansionTile(
leading: CircleAvatar(
radius: 32,
backgroundImage: NetworkImage(
data0[index]
.data()['image_url']
.toString(),
),
),
title: Text(data0[index].data()['username']),
),
);
}),
);
});
});
});

Building future from firebase result

I'm using a future to search firebase for users based on user input. The future then returns the results as a list but the future builder is not working to show the data in the UI. How can I build this data in the UI? Also is using future builder the correct way of doing this?
FutureBuilder(
future: userSearch(_userSearchController.text),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data);
} else {
return new CircularProgressIndicator();
}
},
)
Future userSearch(String userSearch) async {
QuerySnapshot result = await Firestore.instance
.collection("users")
.where("name", isEqualTo: userSearch)
.getDocuments();
final List<DocumentSnapshot> docs = result.documents;
return docs;
}
Edit using Stream
StreamBuilder(
stream: userSearch(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
print(snapshot.data.length);
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return userWidget(snapshot.data[index].data);
});
} else {
return new CircularProgressIndicator();
}
},
)
Stream<dynamic> userSearch() async* {
print("User Search");
QuerySnapshot result = await Firestore.instance
.collection("users")
.where("name", isEqualTo: _userSearchController.text.toLowerCase())
.getDocuments();
yield result.documents;
}
Due to you have catered for search based on userInput, you should be using Streambuilder. Future only return once, but streambuilder will always rebuild your widget whenever the return value is changed.
To build your UI, you can use ListView.builder:
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return BuildYourWidget(snapshot.data[index]);
});
} else {
return CircularProgressionIndicator();
}
BuilYourWidget(dynamic yoursnapshotdata) {
return ListTile(trailing: Text('hello'), title: Text(yoursnapshotdata));
}

Flutter: Firestore Get User uid inside StreamBuilder

I have an app which I want to display documents inside collection.. the collection reference is the uid of the user.
Is there a way to get current user uid and put this uid inside StreamBuilder in stream.
I have tried like so but it did not work and returned null:
class _MyAdsState extends State<MyAds> {
final FirebaseAuth _auth = FirebaseAuth.instance;
Future getCurrentUser() async {
final FirebaseUser user = await _auth.currentUser();
final uid = user.uid;
print(uid);
return uid.toString();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
Expanded(
child: StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection("${getCurrentUser()}").snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> querySnapShot){
if(querySnapShot.hasError){
return Text('Some Error');
}
if(querySnapShot.connectionState == ConnectionState.waiting){
return CircularProgressIndicator();
}else{
final list = querySnapShot.data.documents;
return ListView.builder(
itemBuilder: (context, index){
return ListTile(
title: Text(list[index]["subject"]),
subtitle: Text(list[index]["category"]),
);
},
itemCount: list.length,
);
}
},
)
Getting the UID is an asynchronous operation, so requires a FutureBuilder.
If you want to use the UID to then build a stream, you'll need to have a FutureBuilder for the UID, and then inside of that a StreamBuilder for the stream from the database.
body: FutureBuilder(
future: FirebaseAuth.instance.currentUser(),
builder: (context, AsyncSnapshot<FirebaseUser> snapshot) {
if (snapshot.hasData) {
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection(snapshot.data.uid).snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> querySnapShot){
...
},
)
}
else {
return Text('Loading user data...');
}
THANK YOU GUYS!
I was looking for this for too long now. I had the "problem" that I was recording the senderUID for a sent message only, but of course wanted the Name being displayed in the "sentFrom" field. So I had to query Firestore for the UID and pull out the email. My solution:
FutureBuilder<QuerySnapshot>(
future: _firestore.collection("users").get(),
builder: (context, futureSnapshot) {
if (!futureSnapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
Map<String, String> users = {};
final userData = futureSnapshot.data.docs;
for (var user in userData) {
users[user.id] = user.data()["email"];
}
return StreamBuilder<QuerySnapshot>(
stream: _firestore.collection("messages").snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
// ignore: missing_return
final messages = snapshot.data.docs;
List<Widget> messageWidgets = [];
for (var message in messages) {
final messageText = message.data()["text"];
final messageEmail = users[message.data()["senderUID"]];
messageWidgets
.add(Text("$messageText from $messageEmail"));
}
return Column(children: messageWidgets);
},
);
},
),
I just created a map from the data and used it inside the stream builder. Is there maybe a better solution?

How to display the firebase array in the list view in flutter

Future<List<DocumentSnapshot>> getData() async {
var firestore = Firestore.instance;
QuerySnapshot qn = await firestore
.collection("UserTransactions")
.where("AuthUserId", isEqualTo: userId)
.getDocuments();
return qn.documents;
}
Here I am getting all the documents according to the id, I want to display the transactions which is an array in the List View
FutureBuilder(
future: getData(),
builder: (_, AsyncSnapshot<List<DocumentSnapshot>> snapshot) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (_, index) {
return Text(snapshot.data[index].data["transactions"][index]["Mode"])
})
}
);
I am getting the error:
The getter 'length' was called on null.
Receiver: null
Tried calling: length
How to display those values and also display nothing if the array is blank?
You need to check if data is retrieved all not:
FutureBuilder(
future: getData(),
builder: (_, AsyncSnapshot<List<DocumentSnapshot>> snapshot) {
if(snapshot.hasData){
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (_, index) {
return Text(snapshot.data[index].data["transactions"][index]["Mode"])
}
return CircularProgressIndicator();
}
)
Use snapshot.hasData to check if the data is retrieved and CircularProgressIndicator which will display a loading icon until data is fully retrieved.

Retrieve collection of certain firebase document in flutter

the document name is the auth user but i cant retrive it as index in the firestore i only need to point at the user.uid and retrieve its collection
StreamBuilder(
stream: Firestore.instance.collection("Attendees").snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return new ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.documents.length,
padding: const EdgeInsets.only(top: 5.0),
itemBuilder: (context, index) {
DocumentSnapshot ds = snapshot.data.documents[index];
return new Row(
textDirection: TextDirection.ltr,
children: <Widget>[
Expanded(child: Text(ds['absenceDay'])),
Expanded(child: Text(ds['excuse'])),
],
);
});
}
},
)
Try the following:
getDocument() async {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
return Firestore.instance.collection("Attendees").document(user.uid).snapshots();
}
Then use it in StreamBuilder:
StreamBuilder(
stream: getDocument(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {

Resources