how to query in firebase select condition where date is datenow - firebase

I'm trying to query in my flutter application to show the user's input data that sort by date now. I have tried this
Stream<QuerySnapshot> getUserWorshipSnapshots(BuildContext context) async*{
//final Long server_timestamp = new DateTime.now().isUtc;
var currentTime = new DateTime.now();
final FirebaseUser user = await _auth.currentUser();
final uid = user.uid;
yield* Firestore.instance.collection('user').document(uid).collection('worship').orderBy('dateTime')
.startAt(currentTime).snapshots();}
, and my firebase structure is like this . is there any idea? thank you

You have a users collection and not a user collection, therefore add the missing s:
yield* Firestore.instance.collection('users').document(uid).collection('worship').orderBy('dateTime')

Related

How to also update user's name and image in comments sub-collection in Flutter via Firestore

In my app, users can comment on every post and the comments are stored in the post's sub-collection: 'comments'. Each comments' document contains the poster's username, profile image, user Id, comment Id and some other fields.
So I'm trying to also update each comments' document that contains a current user's userId when that user updates their profile.
I have only been able to achieve the code below;
//Uploading the new image to storage
final firebaseUser = FirebaseAuth.instance.currentUser!;
final String uids = firebaseUser.uid;
final Reference storageReference =
FirebaseStorage.instance.ref().child("userImages- $uids");
UploadTask uploadTask = storageReference.putFile(imageTemp);
String downloadUrl = await (await uploadTask).ref.getDownloadURL();
//Updating users' document with the new image
final CollectionReference users =
FirebaseFirestore.instance.collection("users");
final String uid = firebaseUser.uid;
String url = downloadUrl;
await users.doc(uid).update({'url': url});
//Trying to also update users' comments document with the image
final CollectionReference posts =
FirebaseFirestore.instance.collection("posts");
await posts
.doc()
.collection('comments')
.doc()
.update({'profilePic': url});
How can I possibly achieve this? Any help will be appreciated.
You could do something like this
await users.doc(uid).update({'url': url}).then((value2) {
FirebaseFirestore.instance
.collection('posts')
.doc('postDOCID')
.collection('comments')
.where('uid', isEqualTo: curUserUID)
.get()
.then((value) => value.docs.forEach((element) {
element.data().update('userImageURL', (value) => "url");
}));
});
Basically, what you will need to do is loop through or search with where through post documents where userId = currentUpdatedUID.
Once you find it, loop the list and update each one of them.
Let me know if any issue comes up.
Cheers!!

Using a Firebase Stream as an input for another Stream in Flutter?

Context: I've got two Firebase Streams that work correctly, and they fetch i) a list of user profiles ('users' collection), and ii) a list of locations belonging to each user profile ('locations' collection), and then map them over to a custom User and Location model.
Users stream:
class DatabaseService {
final String uid;
final String friendUid;
final String locationId;
DatabaseService({ this.uid, this.locationId, this.friendUid });
// collection reference for users
final CollectionReference userCollection = FirebaseFirestore.instance.collection('users');
// get users stream
Stream<List<CustomUserModel>> get users {
final FirebaseAuth auth = FirebaseAuth.instance;
final User user = auth.currentUser;
final uid = user.uid;
List<CustomUserModel> userList = [];
List<CustomUserModel> _streamMapper(DocumentSnapshot snapshot) {
CustomUserModel individualUser = CustomUserModel(
uid: snapshot.id,
name: snapshot.data()['name'],
username: snapshot.data()['username'],
email: snapshot.data()['email'],
);
userList.add(individualUser);
return userList;
}
return userCollection.doc(uid).snapshots().map(_streamMapper);
}
and the Location Stream:
// collection reference for location
final CollectionReference locationCollection =
FirebaseFirestore.instance.collection('locations');
Stream<List<Location>> get locations {
final FirebaseAuth auth = FirebaseAuth.instance;
final User user = auth.currentUser;
final uid = user.uid;
List<Location> _locationListFromSnapshot(QuerySnapshot snapshot) {
List<Location> locationList = [];
snapshot.docs.forEach((element) {
Location individualLocation = Location(
locationId: element.id,
locationName: element.data()['locationName'],
city: element.data()['city'],
);
locationList.add(individualLocation);
});
return locationList;
}
return userLocationCollection.doc(uid).collection('locations').snapshots()
.map(_locationListFromSnapshot);
}
What I want to do is to generate a custom Stream which outputs all the locations for all users - in other words to use the users stream as an input for the locations stream.
I'm not sure what approach works here - I considered adding the users stream as an input parameter to the locations stream and then creating a for-loop, something like this:
Stream<List<Location>> allLocations(Stream<List<CustomUserModel>> users) {
final FirebaseAuth auth = FirebaseAuth.instance;
final User user = auth.currentUser;
final uid = user.uid;
List<Location> locationList = [];
users.forEach((element) {
// append user's locations to empty list
locationList.add(locationCollection.doc(element.first.uid).collection('locations')
.snapshots().map(SOME FUNCTION TO MAP A DOCUMENT SNAPSHOT TO THE CUSTOM LOCATION MODEL)
}
return locationList;
but of course I get an error as this returns a list, not a stream. So I've no idea how to proceed...
I hear your pain. I have been there. You were pretty close. Let me explain how I like to do it.
First of all, some clean up:
It seemed like you were not using these in the allLocations functions, so I deleted them
final FirebaseAuth auth = FirebaseAuth.instance;
final User user = auth.currentUser;
final uid = user.uid;
Second, I changed the return type of the function from Stream<List<Location>> to Stream<Map<String, List<Location>> where the key of the map would be the userId. I find this type useful, because you don't have to worry about the order of users being in sync with the stream.
Third, when you are creating streams, you cannot return, but have to yield from a function. You also have to mark the function async* (* is not a typo).
With this, I propose you use something like this for your allLocations function:
class DataService {
List<Location> convertToLocations(QuerySnapshot snap) {
// This is the function to convert QuerySnapshot into List<Location>
return [Location()];
}
Stream<Map<String, List<Location>>> allLocations(
Stream<List<CustomUserModel>> usersStream) async* {
Map<String, List<Location>> locationsMap = {};
await for (List<CustomUserModel> users in usersStream) {
for (CustomUserModel user in users) {
final Stream<List<Location>> locationsStream = locationCollection
.doc(user.uid)
.collection('locations')
.snapshots()
.map(convertToLocations);
await for (List<Location> locations in locationsStream) {
locationsMap[user.uid] = locations;
yield locationsMap;
}
}
}
}
}
I hope you like this method. Please let me know if something is not what you want. I can make adjustments.

Flutter and Firebase: Get DocumentSnapShot Based On Current User ID

Here's my code to get current user documentsnapshot from database.
Future getCurrentUSerData() async {
final DocumentSnapshot doc = await userRef.document(currentUserId).get();
currentUser = MyUser.fromDocument(doc);
}
I got the currentUserId. there is no problem with that.
2.userRef is the reference to the users in firebase (final userRef = Firestore.instance.collection('users');)
but when I checked currentUser value, the value is returned as null.
Problem - How to get the current user data based on current user id?
Please change
final DocumentSnapshot doc = await userRef.document(currentUserId).get();
to
final DocumentSnapshot doc = await userRef.doc(currentUserId).get();

Flutter place filter based on variable in firestore request

I am working on an app which requests based on the registered Userid certain elements from my firestore.
Now i'm trying to build the Notifier related to this but somehow it breaks when putting the filter in the firestore request
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:tutora/states/question_notifier.dart';
import 'package:tutora/models/answers.dart';
import 'package:firebase_auth/firebase_auth.dart';
Future<String> id() async {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
String userID = user.uid.toString();
return userID;
}
getAnswers(AnswerNotifier answerNotifier) async {
QuerySnapshot snapshot = await Firestore.instance
.collection('Questions')
.where(
'UserID',
isEqualTo: await id(),
)
.getDocuments();
List<Answer> _answerList = [];
snapshot.documents.forEach((document) {
Answer answer = Answer.fromMap(document.data);
_answerList.add(answer);
});
answerNotifier.answerList = _answerList;
}
What in my head this should do is that it gets the current user ID and then based on that ones only collects the Questions which match on the column UserID.
This works perfectly fine if i manually enter the UserID in my code however the moment where it requests the current user ID from id() it does not find any matching questions. So my question list in the app is empty as well as ofc my _answerList here.
The user is logged in at this point in the app where this Answernotifier is called.
Thankful for any help this is really bugging me now quit some time.
Try the following:
getAnswers(AnswerNotifier answerNotifier) async {
String userId = await id();
QuerySnapshot snapshot = await Firestore.instance
.collection('Questions')
.where('UserID',isEqualTo: userId).getDocuments();
get the userId first and then use the result inside the where() query.

How to display list of documents data from collection named by date?

//how to display all documents data from all collections? I set the name of each collection by date. This only get the latest data by date.
var now = new DateTime.now();
var formatter = new DateFormat('yyyy-MM-dd');
String formatted = formatter.format(now);
final FirebaseAuth firebaseAuth = FirebaseAuth.instance;
final FirebaseUser user = await firebaseAuth.currentUser();
final uid = user.uid;
QuerySnapshot qn = await db
.collection('history')
.document(uid)
.collection('$formatted')
.orderBy('createdAt', descending: true)
.getDocuments();
yield qn.documents;
}
It is not possible for a single query to span multiple collections with different names. The only exception to this is collection group queries which consider documents across multiple collections with the exact same name.
If you want data from multiple collections, you will have to issue a query for each collection, then merge the results in the client app.

Resources