How to loop through Instance of '_MapStream<QuerySnapshotPlatform, QuerySnapshot<Map<String, dynamic>>>'? - flutter

static List categoryList() {
final categorySnapshots = FirebaseFirestore.instance
.collection('categories')
.orderBy('name')
.snapshots();
List categories = [];
categorySnapshots.map((snapshot) => snapshot.docs.map((doc) {
print(snapshot.toString());
categories.add(doc.data()['name']);
}));
print(categories);
return categories;
}
Categories is empty.
How to populate it with the data from snapshots?

I added a new collection called "school", there're two items added inside the document.
void getMessagesTest() async{
QuerySnapshot querySnapshot = await _firestore.collection('school').orderBy('age',descending: true).get();
final allData = querySnapshot.docs.map((doc) => doc.data()).toList();
print(allData);
}
I used my code, and it works. Could you please remove ".where" and try it again?
You could chain where and orderBy together. Please see my code below. Reference link => Using Where and Order by different fields in Firestore query
void getMessagesTest() async{
QuerySnapshot querySnapshot = await _firestore.collection('school').orderBy('age', descending: true).where('age', isGreaterThan: 17).get();
final allData = querySnapshot.docs.map((doc) => doc.data()).toList();
print(allData);
}

Using the below code might help
you can convert the snapshot to Map<String,dynamic> by using the following function:
static Post fromSnap(DocumentSnapshot snap) {
var snapshot = snap.data() as Map<String, dynamic>;
}

Related

How to fetch a `DocumentReference` from a Firebase `get()`

I have a collection ads that contains a DocumentReference as ownerId.
With the code below, I am able to fetch the 10 most recent ads as aList<Ad>:
/// Returns a list of ads of the given [category]
static Future<List<ClassifiedAd>> getFromCategory(
ClassifiedAdCategory category,
{int max = 10}) async {
return FirebaseFirestore.instance
.collection('ads')
.where('category', isEqualTo: category.name)
.orderBy('creationDate', descending: true)
.limit(max)
.get()
.then((snapshot) {
return snapshot.docs.map((doc) {
final data = doc.data();
return Ad.fromMap(data);
}).toList();
});
But now I'd like to fetch the owner (collection users) from the DocumentReference I was talking about above. But I am a but puzzled about how to do that.
My modified code below does not compile:
The return type 'List' isn't a 'FutureOr<List>', as required by the closure's context.
/// Returns a list of ads of the given [category]
static Future<List<ClassifiedAd>> getFromCategory(
ClassifiedAdCategory category,
{int max = 10}) async {
return FirebaseFirestore.instance
.collection('ads')
.where('category', isEqualTo: category.name)
.orderBy('creationDate', descending: true)
.limit(max)
.get()
.then((snapshot) {
// <<<< Error starts right here down to the removeWhere()
return snapshot.docs.map((doc) {
final data = doc.data();
final DocumentReference docRef = data["ownerId"];
return docRef.get().<ClassifiedAd?>then((snapshot) {
if (snapshot.exists) {
return ClassifiedAd.fromMap(data);
}
return null;
});
}).toList()
// Don't take into account potential nulls
..removeWhere((a) => a == null);
});
How should I do that?
I would say that the wrong thing that you're doing is you're trying to get a snapshot asynchronously inside the map() method which is synchronous, for such cases like yours, I recommend using await/async and to not return anything until you guarantee that you got it, try this:
static Future<List<ClassifiedAd>> getFromCategory(
ClassifiedAdCategory category,
{int max = 10}) async {
final snapshot = await FirebaseFirestore.instance
.collection('ads')
.where('category', isEqualTo: category.name)
.orderBy('creationDate', descending: true)
.limit(max)
.get();
List<ClassifiedAd> result = [];
for (int index = 0; index < snapshot.docs.length; index++) {
final doc = snapshot.docs[index];
final data = doc.data();
final DocumentReference docRef = data["ownerId"];
final docOwnerSnapshot = await docRef.get();
if (docOwnerSnapshot.exists) {
result.add(ClassifiedAd.fromMap(data));
}
}
return result;
}

How can i manually add document-fields into local QueryDocumentSnapshot List

i have the following list
List <QueryDocumentSnapshot> globalVideosUrls = [] ;
for example if we use the following
FirebaseFirestore.instance.collection('users')
.limit(1).get().then((value){
globalVideosUrls.add(value)
});
it will add as expected
but what if i want to manually add the following data into globalVideosUrls
document id
00dcb026-3163-4ca0-859e
fields
'videoType':'peace'
'url':'url'
.
globalVideosUrls.add(????)
You have to replace the type "QueryDocumentSnapshot" with QuerySnapshot and then you will get multiple docs and with there data also try this If any questions then ask.
thanks🙏.
List<QuerySnapshot> globalVideosUrls = [];
List<String> videoUrlList = [];
await FirebaseFirestore.instance
.collection('users')
.get()
.then((value) {
globalVideosUrls.add(value);
});
globalVideosUrls.forEach((element) {
element.docs.forEach((docELe) {
print("data:- ${docELe.data()}");
Map map = docELe.data() as Map;
videoUrlList.add(map['url']);
});
});

How to return a Stream using an async* function in Flutter

I am working on a chat app using Flutter and Firebase. I am new to Dart and so got stuck when I wanted to create a function which fetches (using await) a particular document from one collection (forums) and use an array property of the forum document to query and return a Stream from another collection (openMessages). The problem with my current solution is that it always returns an empty array. I am sure I am using the keywords or logic incorrectly. Can you please help me refactor my method.
Stream<List<ChatMessage>> getForumChatStream(String forumId) async* {
List<ChatMessage> messages = [];
var docSnap = await firestore.collection('forums').doc(forumId).get();
Forum forum = Forum.fromMap(docSnap.data()!);
firestore
.collection('openMessages')
.where('messageId', whereIn: forum.messageIds)
.orderBy('timeSent', descending: true)
.snapshots()
.map((event) {
for (var document in event.docs) {
messages.add(ChatMessage.fromMap(document.data()));
}
});
//print('LENGTH:'+messages.length.toString());
yield messages;}
You can use the following method.
Stream<List<ChatMessage>> getForumChatStream(String forumId) async* {
final firestore = FirebaseFirestore.instance;
List<ChatMessage> messages = [];
var docSnap = await firestore.collection('forums').doc(forumId).get();
Forum forum = Forum.fromMap(docSnap.data()!);
final result = firestore
.collection('openMessages')
.where('messageId', whereIn: forum.messageIds)
.orderBy('timeSent', descending: true)
.snapshots();
await for (final r in result) {
final docs = r.docs;
for (final document in docs) {
messages.add(ChatMessage.fromMap(document.data()));
yield messages;
}
}
}
Or
Stream<List<ChatMessage>> getForumChatStream(String forumId) async* {
final firestore = FirebaseFirestore.instance;
List<ChatMessage> messages = [];
var docSnap = await firestore.collection('forums').doc(forumId).get();
Forum forum = Forum.fromMap(docSnap.data()!);
yield* firestore
.collection('openMessages')
.where('messageId', whereIn: forum.messageIds)
.orderBy('timeSend', descending: true)
.snapshots()
.map((event) =>
event.docs.map((e) => ChatMessage.fromMap(e.data())).toList());
}

flutterfire where and orderby not return data

i have implemented this code for retrieving the messages of this room.
final messagesProvider = StreamProvider((ref) {
FirebaseFirestore db = FirebaseFirestore.instance;
var room = ref.watch(roomIdProvider);
print('room updated');
print('room is '+room);
final docRef = db
.collection("messages")
.where("chat_room_id",isEqualTo: room)
// .orderBy('created_at')
// .orderBy('created_at',descending: true)
;
print(docRef.orderBy("created_at").snapshots());
return docRef.snapshots();
});
i want to sort the data and have tried these two lines separately but not worked for me
.orderBy('created_at')
.orderBy('created_at',descending: true)
where created at is a timestamp field.
I added a new collection called "school", there're two items added inside the document.
I used my code, and it works. Could you please remove ".where" and try it again?
void getMessagesTest() async{
QuerySnapshot querySnapshot = await _firestore.collection('school').orderBy('age',descending: true).get();
final allData = querySnapshot.docs.map((doc) => doc.data()).toList();
print(allData);
}
Updated 20220616:
Updated 20220618:
Yes, you could chain where and orderBy together. Please see my code below.
Reference link => Using Where and Order by different fields in Firestore query
void getMessagesTest() async{
QuerySnapshot querySnapshot = await _firestore.collection('school').orderBy('age', descending: true).where('age', isGreaterThan: 17).get();
final allData = querySnapshot.docs.map((doc) => doc.data()).toList();
print(allData);
}

How to get firestore data as stream?

I am making a collection group query, where upon matching a particular field, I am going a level backwards and then read the data.
I am able to do that in Future approach.
Here is my code returning future:
#override
Future<Either<JobPostFailure, List<JobPost>>> readAppliedJobPosts({
required String seamanId,
}) async {
final querySnapshot = await FirebaseFirestore.instance
.collectionGroup(ConstStrings.applications)
.where(
ConstStrings.seamanId,
isEqualTo: seamanId,
)
.get();
final List<JobPost> mList = [];
for (var docSnap in querySnapshot.docs) {
final jobPostDocSnap = await docSnap.reference.parent.parent?.get();
mList.add(JobPostDto.fromFirestore(jobPostDocSnap!).toDomain());
}
return right(mList);
}
Now I am struggling to do this in Stream approach, where my return type would be something like this : Stream<Either<JobPostFailure, List<JobPost>>>. What is the equivalent of my above code in Stream?
My try so far :
#override
Stream<Either<JobPostFailure, List<JobPost>>> watchAppliedJobPosts({
required String seamanId,
}) async* {
yield* _firestore
.collectionGroup(ConstStrings.applications)
.where(
ConstStrings.seamanId,
isEqualTo: seamanId,
)
.snapshots()
.map((event) {
return event.docs.map((e) {
return e.reference.parent.parent!.snapshots().map((event) {
return right(JobPostDto.fromFirestore(event).toDomain());
}).toList();
});
});
}
And its a big mess!
You can use method snapshots instead of get. Is will create a new stream that will fetch data for every change your document or collection has