How to change my future method into stream method? - firebase

Im displaying my videos collection where each video has a ratingbarfield. The Videos are displayed inside streambuilder.So my problem is that my method is a future method I need to change that into a stream also .
Heres my method
onTap: () async {
} else {
final value =
await FirebaseFirestore
.instance
.collection("videos")
.doc(videos.data()['id'])
.collection("uservotes")
.doc(uid)
.get();
setState(() {
votefromfirebase =
value.data()["rating"];
israting = true;
});
}
},
Hope anyone can help .

In FirebaseFirestore the CollectionReference and DocumentReference provide a snapshots() method which returns a Stream:
final videoDocumentStream = await FirebaseFirestore
.instance
.collection("videos")
.doc(videos.data()['id'])
.collection("uservotes")
.doc(uid)
.snapshots();
to listen for a stream it is likely to use a StreamBuilder:
StreamBuilder<QuerySnapshot>(
stream: videoDocumentStream.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
var userDocument = snapshot.data();
return Text(userDocument["rating"]);
},
)

Related

Convert method into FutureBuilder : Flutter

I'm new to flutter. This is the method that I used to retrieve the data from firebase and I'm able to get the exact answer in the console. My question is how I can convert this code into future builder so I am able to read the data in my application.
void getUser() async {
firestoreInstance.collection("User Data").get().then((querysnapshot) {
querysnapshot.docs.forEach((result) {
firestoreInstance
.collection("User Data")
.doc(result.id)
.collection("bank")
.where('account_username', isEqualTo: ownerData?.name2)
.get()
.then((query Snapshot) {
querysnapshot.docs.forEach((result) {
print (result["bank_name"]);
});
});
});
});
}
You should return the value from the query, not print it
Your function should look like this
Future<String> getUser() async {
firestoreInstance.collection("User Data").get().then((querysnapshot) {
querysnapshot.docs.forEach((result) {
firestoreInstance
.collection("User Data")
.doc(result.id)
.collection("bank")
.where('account_username', isEqualTo: ownerData?.name2)
.get()
.then((query Snapshot) {
querysnapshot.docs.forEach((result) {
return result["bank_name"];
});
});
});
});
}
The Futurebuilder should look like this
FutureBuilder<String>(
future: getUser(), // async work
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting: return Text('Loading....');
default:
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
else
return Text('Result: ${snapshot.data}');
}

Stream provider is not filtering data according to where clause that I specified,

I have a stream provider that should return userData of the current logged in user. It should take information of user whose email is equal to current user.email.I guess the stream provider load data before the email of the current user is saved b'se it load information of all users `. So how should I make stream provider to wait until the email of the current user is saved .
The function that load current user.
Future<void>loadLoggedUser() async{
FirebaseAuth.instance
.userChanges()
.listen((User? user) {
if (user == null) {
print('User is currently signed out!');
} else {
email=user.email;
userid=user.uid;
print('User is signed in!');
}
});
notifyListeners();
}
Stream provider for userData
Stream<List<UserData>> get UserList {
return _db.collection('users').where('email', isEqualTo: email)
.snapshots()
.map((snapshot) =>
snapshot.docs
.map((document) =>
UserData.fromJson(document.data())).toList()
);
}
Any help will be appreciated
You can also search like this if you want -
Nested Streambuilder can help to achieve this sorting and searching problem.
1st StreamBuilder is of User and second for QuerySnapshot<Map<String, dynamic>>
StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<User?> snapshot) {
if (snapshot.hasData) {
final String email = snapshot.data!.email;
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('users')
.where('email', isEqualTo: email)
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>>
snapshot) {
if (snapshot.hasData) {
final list = snapshot.data!.docs
.map((document) => UserData.fromJson(document.data()))
.toList();
if (list.isNotEmpty) {
return ListView.builder(
shrinkWrap: true,
itemCount: list.length,
itemBuilder: (BuildContext context, int index) {
final userData = list[index];
return Text(userData
.name); // can print properties of userData model
},
);
}
return const Text("NO DATA AVAILABLE");
}
return const Text("Loading");
},
);
}
return const Center(
child: Text("logged out"),
);
},
),
I would suggest turning getter into a function and checking if user email is null or empty string (depending on how you initialise it in your code).
Stream<List<UserData>> getUserList(String? email) {
if (email == null) throw Exception("Email is null");
return _db
.collection('users')
.where('email', isEqualTo: email)
.snapshots()
.map((snapshot) => snapshot.docs
.map((document) => UserData.fromJson(document.data()))
.toList());
}

How to retreive data from firestore flutter

I'm new into flutter and firebase integrations and I'm having some troubles to retreive all the data from the firebase collection.
I have tried this method:
getCollection() {
CollectionReference coleccion =
FirebaseFirestore.instance.collection('materias');
return Container(
child: StreamBuilder(
stream: coleccion.doc('aprobadas').snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
return Text(snapshot.data.data()['codigo'],
style: TextStyle(fontSize: 50, color: Colors.white));
} else {
return CircularProgressIndicator();
}
},
),
);
}
Now I'm a little bit frustrated because I have tried a differents methods and doesn't work.
I really appreciate all the help.
Best regards
Data can be retrieved using the below code from firestore to flutter.
One-time Read
call the Query.get or DocumentReference.get methods
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");
},
);
}
}
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();
Please refer official documentation here
You can use a StreamBuilder. That will be easy to understand.
StreamBuilder(
stream: FirebaseFirestore.instance.collection("collection").snapshot,
builder: (BuildContext context,snapshot) {
if(snapshot.hasdata!=true) {
return CircularProgressIndicator();
} else {
return ListView.builder(
itemcount:snapshot.data.docs.length,
builder(context,index) {
return Text(snapshot.data.docs[index].data()["filedname"]);
}
}
)

Flutter - Class 'DocumentSnapshot' has no instance getter 'docs'

I have 2 streams in my codes the first one is to get the userid from friend list and the second stream is to use the list of ids to search for the userid's document in firebase.
Stream friendIDStream;
Stream friendNameStream;
Widget friendList() {
return StreamBuilder(
stream: friendNameStream,
builder: (context, snapshot) {
return snapshot.hasData
? ListView.builder(
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index) {
return FriendTile(
snapshot.data.docs[index].data()["username"]);
},
)
: Container();
},
);
}
#override
void initState() {
getUserFriend();
getNameByID();
super.initState();
}
getUserFriend() async {
Constant.currentId =
await HelperFunctions.getUserIdSharedPreference(Constant.currentId);
setState(() {
firebaseMethods.getFriend(Constant.currentId).then((value) {
setState(() {
friendIDStream = value;
});
});
});
}
getNameByID() {
setState(() {
firebaseMethods.getFriendName(friendIDStream).then((value) {
setState(() {
friendNameStream = value;
});
});
});
}
This is the firestore code.
Future getFriend(String ownerid) async {
return await FirebaseFirestore.instance
.collection("users")
.doc(ownerid)
.collection("friends")
.snapshots();
}
Future getFriendName(friendid) async {
return await FirebaseFirestore.instance
.collection("users")
.doc(friendid)
.snapshots();
}
I doesn't know why is this happening since I can display the list of ids. I had tried changing docs to doc but is also produce the same error.
Edit:
Added photos of my database structure.
the reason is your function getFriendName is returning a documentsnapshot not a querysnapshot. SO replace your old code with this:-
Widget friendList() {
return StreamBuilder(
stream: friendNameStream,
builder: (context, snapshot) {
return snapshot.hasData
? ListView.builder(
itemCount: 1,
itemBuilder: (context, index) {
return FriendTile(
//snapshot.data.docs[index].data()["username"] old one
snapshot.data["username"]); //new one
},
)
: Container();
},
);
}

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

Resources